fix(deploy): keep D1 ids out of fork config

This commit is contained in:
tianma-if committed 2026-08-17 15:00:51 +08:00
1 parent 5f0b3947ce
commit ed8a7ac7bd
7 files changed
+66 -11

No files matched your search

+1 -1
View File
@@ -36,7 +36,7 @@ This document defines the standard operating specifications and conventions for
Deploy command: bun run deploy:cloudflare-builds
```
- The deploy command automatically resolves the D1 UUID from the `edgeever` database name and writes it only to a temporary generated Wrangler configuration. Users do not need to edit `wrangler.toml` or copy a D1 ID into a build variable.
- The deploy command automatically resolves the D1 UUID from the `edgeever` database name and writes it only to a temporary generated Wrangler configuration. The tracked `wrangler.toml` must keep its all-zero `database_id` placeholder; deployment rejects an instance-specific ID committed there so a Fork cannot diverge on local infrastructure configuration.
- Ensure the Workers Builds API token can read and edit D1. An advanced deployment that uses a differently named database must set the build variable `EDGE_EVER_D1_DATABASE_ID` explicitly.
6. **Start Initial Build & Verify Service**
+1 -1
View File
@@ -36,7 +36,7 @@
Deploy command: bun run deploy:cloudflare-builds
```
- 部署命令会根据 `edgeever` 数据库名称自动查询 D1 UUID,并且只写入临时生成的 Wrangler 配置。用户无需修改 `wrangler.toml`,也无需手工把 D1 ID 复制到构建变量。
- 部署命令会根据 `edgeever` 数据库名称自动查询 D1 UUID,并且只写入临时生成的 Wrangler 配置。受版本控制的 `wrangler.toml` 必须保留全零 `database_id` 占位符;若把实例专属 ID 提交到该文件,部署会直接拒绝,避免 Fork 因本地基础设施配置产生分叉。
- 请确保 Workers Builds API Token 具有 D1 读取和编辑权限。使用其他数据库名称的高级部署需要显式设置构建变量 `EDGE_EVER_D1_DATABASE_ID`。
6. **启动首次构建与服务验证**
+1 -1
View File
@@ -69,7 +69,7 @@ Deploy command: bun run deploy:cloudflare-builds
Click **Save and Deploy** to trigger the initial build.
The deploy command automatically looks up the D1 UUID by the `edgeever` database name. Do not edit `wrangler.toml` or manually copy the D1 ID. The Workers Builds API token must have D1 read/edit permission.
The deploy command automatically looks up the D1 UUID by the `edgeever` database name. Keep the tracked `wrangler.toml` on its all-zero `database_id` placeholder; deployment rejects an instance-specific ID committed there. The Workers Builds API token must have D1 read/edit permission.
After publishing, the CI deployment records the actual public target reported by Wrangler and requests its `/api/health` endpoint. The build fails if the live Worker is missing its `DB` binding, uses an unprepared D1 database, or does not return a healthy response.
+1 -1
View File
@@ -69,7 +69,7 @@ Deploy command: bun run deploy:cloudflare-builds
点击 **Save and Deploy** 启动首次构建部署。
部署命令会根据 `edgeever` 数据库名称自动查询 D1 UUID。无需修改 `wrangler.toml`,也无需手工复制 D1 ID。Workers Builds API Token 必须具有 D1 读取和编辑权限。
部署命令会根据 `edgeever` 数据库名称自动查询 D1 UUID。受版本控制的 `wrangler.toml` 必须保留全零 `database_id` 占位符;若把实例专属 ID 提交到该文件,部署会直接拒绝。Workers Builds API Token 必须具有 D1 读取和编辑权限。
发布完成后,CI 部署会记录 Wrangler 返回的实际公网入口,并请求该入口的 `/api/health`。如果线上 Worker 缺少 `DB` binding、绑定了未初始化的 D1,或没有返回健康状态,构建会直接失败。
+13 -3
View File
@@ -4,6 +4,7 @@ import {
readFileSync,
readdirSync,
rmSync,
writeSync,
writeFileSync,
} from "node:fs";
import { dirname, resolve } from "node:path";
@@ -13,12 +14,13 @@ import {
findD1DatabaseIdByName,
normalizeD1MigrationSql,
parseWranglerDeploymentUrls,
PLACEHOLDER_D1_ID,
repositoryD1ConfigError,
runWranglerSync,
shouldCaptureDeploymentTargets,
} from "./wrangler-runner.mjs";
import { writeWranglerNotice } from "./wrangler-output.mjs";
const PLACEHOLDER_D1_ID = "00000000-0000-0000-0000-000000000000";
const UUID_PATTERN =
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -72,7 +74,9 @@ if (requestedInstance !== undefined) {
process.env.EDGE_EVER_INSTANCE = requestedInstance;
}
const baseConfigPath = resolve(process.env.WRANGLER_CONFIG ?? "wrangler.toml");
const repositoryConfigPath = resolve("wrangler.toml");
const baseConfigPath = resolve(process.env.WRANGLER_CONFIG ?? repositoryConfigPath);
const usesRepositoryConfig = baseConfigPath === repositoryConfigPath;
const baseConfigDirectory = dirname(baseConfigPath);
const instance = process.env.EDGE_EVER_INSTANCE?.trim();
const instanceKey = instance?.replace(/[^a-zA-Z0-9]/g, "_").toUpperCase();
@@ -90,6 +94,12 @@ const generatedLocalDevEnvPath = resolve(".env.wrangler.generated.local");
let config = readFileSync(baseConfigPath, "utf8");
let changed = false;
const d1ConfigError = repositoryD1ConfigError(config, usesRepositoryConfig);
if (d1ConfigError) {
writeSync(2, `${d1ConfigError}\n`);
process.exit(1);
}
const migrationCommand =
wranglerArgs[0] === "d1"
&& wranglerArgs[1] === "migrations"
@@ -306,7 +316,7 @@ if (isRemoteCommand && config.includes(`database_id = "${PLACEHOLDER_D1_ID}"`))
instanceKey
? `Set EDGE_EVER_${instanceKey}_D1_DATABASE_ID or EDGE_EVER_D1_DATABASE_ID,`
: "Set EDGE_EVER_D1_DATABASE_ID,",
"or replace the database_id placeholder in wrangler.toml / WRANGLER_CONFIG.",
"or point WRANGLER_CONFIG at an external configuration file with the required binding.",
].join(" "),
);
process.exit(1);
+16
View File
@@ -2,6 +2,22 @@ import { spawnSync } from "node:child_process";
import { existsSync, readFileSync } from "node:fs";
import { resolve } from "node:path";
export const PLACEHOLDER_D1_ID = "00000000-0000-0000-0000-000000000000";
export const repositoryD1ConfigError = (config, usesRepositoryConfig) => {
if (!usesRepositoryConfig) return undefined;
const configuredId = config.match(/^database_id\s*=\s*"([^"]+)"/m)?.[1];
if (configuredId === PLACEHOLDER_D1_ID) return undefined;
return [
"Refusing to use an instance-specific D1 database id from the repository wrangler.toml.",
`Restore database_id to "${PLACEHOLDER_D1_ID}".`,
"Provide the real id through EDGE_EVER_D1_DATABASE_ID, let deployment resolve it by database name,",
"or point WRANGLER_CONFIG at an external configuration file.",
].join(" ");
};
export const resolveWranglerCliPath = (cwd = resolve(".")) =>
resolve(cwd, "node_modules", "wrangler", "bin", "wrangler.js");
+33 -4
View File
@@ -15,6 +15,7 @@ import {
manualDeploymentCopy,
} from "../apps/site/src/deployment-prompts";
import { decideUpstreamSync } from "../scripts/upstream-sync-plan.mjs";
import { repositoryD1ConfigError } from "../scripts/wrangler-runner.mjs";
const repositoryRoot = resolve(import.meta.dir, "..");
const normalizeLineEndings = (value: string) => value.replace(/\r\n/g, "\n");
@@ -123,15 +124,43 @@ describe("Cloudflare deployment entrypoints", () => {
test("online deployment resolves the D1 id without editing the repository config", () => {
const runner = readRepositoryFile("scripts/run-wrangler.mjs");
const wranglerConfig = readRepositoryFile("wrangler.toml");
const englishAgentDoc = readRepositoryFile("docs/agent-deploy-cloudflare.md");
const chineseAgentDoc = readRepositoryFile("docs/agent-deploy-cloudflare.zh-CN.md");
expect(wranglerConfig).toContain(
'database_id = "00000000-0000-0000-0000-000000000000"',
);
expect(runner).toContain('"d1", "list", "--json"');
expect(runner).toContain("findD1DatabaseIdByName");
expect(runner).toContain("repositoryD1ConfigError(config, usesRepositoryConfig)");
expect(runner).not.toContain("replace the database_id placeholder");
expect(englishAgentDoc).toContain("automatically resolves the D1 UUID");
expect(chineseAgentDoc).toContain("自动查询 D1 UUID");
});
test("rejects an instance-specific D1 id in the repository Wrangler config", () => {
const instanceConfig = [
'name = "edgeever"',
'database_name = "edgeever"',
'database_id = "11111111-1111-1111-1111-111111111111"',
"",
].join("\n");
const placeholderConfig = instanceConfig.replace(
"11111111-1111-1111-1111-111111111111",
"00000000-0000-0000-0000-000000000000",
);
const error = repositoryD1ConfigError(instanceConfig, true);
expect(error).toContain(
"Refusing to use an instance-specific D1 database id from the repository wrangler.toml",
);
expect(error).toContain("EDGE_EVER_D1_DATABASE_ID");
expect(error).toContain("WRANGLER_CONFIG");
expect(repositoryD1ConfigError(placeholderConfig, true)).toBeUndefined();
expect(repositoryD1ConfigError(instanceConfig, false)).toBeUndefined();
});
test("keeps D1 resolver diagnostics out of Wrangler JSON stdout", () => {
const workingDirectory = mkdtempSync(resolve(tmpdir(), "edgeever-wrangler-output-"));
const wranglerBinDirectory = resolve(
@@ -149,13 +178,13 @@ describe("Cloudflare deployment entrypoints", () => {
const environment = {
...inheritedEnvironment,
EDGE_EVER_INSTANCE: "",
WRANGLER_CONFIG: resolve(workingDirectory, "wrangler.toml"),
WRANGLER_CONFIG: resolve(workingDirectory, "wrangler.external.toml"),
};
try {
mkdirSync(wranglerBinDirectory, { recursive: true });
writeFileSync(
resolve(workingDirectory, "wrangler.toml"),
resolve(workingDirectory, "wrangler.external.toml"),
[
'name = "edgeever"',
'database_name = "edgeever"',
@@ -255,7 +284,7 @@ describe("Cloudflare deployment entrypoints", () => {
try {
mkdirSync(wranglerBinDirectory, { recursive: true });
writeFileSync(
resolve(workingDirectory, "wrangler.toml"),
resolve(workingDirectory, "wrangler.external.toml"),
[
'name = "edgeever"',
"workers_dev = true",
@@ -288,7 +317,7 @@ describe("Cloudflare deployment entrypoints", () => {
CI: "true",
EDGE_EVER_AUTH_PASSWORD: "test-password",
EDGE_EVER_INSTANCE: "",
WRANGLER_CONFIG: resolve(workingDirectory, "wrangler.toml"),
WRANGLER_CONFIG: resolve(workingDirectory, "wrangler.external.toml"),
},
},
);