fix(deploy): keep D1 ids out of fork config
This commit is contained in:
1 parent
5f0b3947ce
commit
ed8a7ac7bd
7 files changed
+66
-11
No files matched your search
@@ -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**
|
||||
|
||||
@@ -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. **启动首次构建与服务验证**
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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,或没有返回健康状态,构建会直接失败。
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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"),
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user