Log SpacetimeDB database names in Jenkins deploy
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-30 09:45:47 +08:00
parent 805d6f8cae
commit 12f68ca614
8 changed files with 53 additions and 13 deletions

View File

@@ -25,7 +25,8 @@
9. 由于 Jenkins Pipeline 的 `build` 步骤触发下游时,原因类型通常是 `org.jenkinsci.plugins.workflow.support.steps.build.BuildUpstreamCause`,实现上需要同时兼容它和经典的 `hudson.model.Cause$UpstreamCause`,否则会把真实的上游触发误判成人工执行。
10. 如果线上进程的启停必须经过 `sudo`,只允许 `start.sh` / `stop.sh` 这两个 hook 使用 `sudo -n` 执行,部署目录清空与文件覆盖仍保持普通权限。
11. `WEB_PORT` 必须在 `构建并部署``部署` 两条流水线之间使用同名参数传递;部署脚本会把最终端口写入固定部署目录 `.env.local``GENARRATIVE_WEB_PORT`,避免 `sudo` 启动 hook 时环境变量被清理导致端口回退。
12. `DATABASE` 必须使用 SpacetimeDB CLI 可接受的名称字符:数字、字母、点和短横线;不要使用下划线,否则 `spacetime publish` 会报 `invalid characters in database name`
12. `DATABASE` 必须匹配 SpacetimeDB CLI 数据库名规则 `^[a-z0-9]+(-[a-z0-9]+)*$`:只能使用小写字母、数字,并用单个短横线分隔;大写字母、点号、下划线、首尾短横线和连续短横线都会被拒绝,否则 `spacetime publish` 会报 `invalid characters in database name`
13. Jenkins 日志必须能看到构建参数中的 SpacetimeDB 发布数据库,以及 `start.sh` 最终加载环境文件后的运行时数据库、server 和 root-dir避免 `.env.local` 覆盖默认值后无法判断实际发布目标。
## 3. 节点与工作区要求
@@ -123,7 +124,8 @@ jenkins/Jenkinsfile.build-and-deploy
3. 归档 `build/<BUILD_VERSION>/**`
4. 记录当前 `NODE_NAME`、源码根目录、版本号。
5. 构建时额外透传 `--web-port <WEB_PORT>`,默认生成监听 `25001` 的发布包。
6. 触发 `部署` 流水线,并传递:
6. 构建日志会输出 `SpacetimeDB 发布数据库: <DATABASE>`,发布包启动日志会输出最终 `database/server/root-dir`
7. 触发 `部署` 流水线,并传递:
- `BUILD_VERSION`
- `SOURCE_WORKSPACE_ROOT`
- `SOURCE_NODE_NAME`
@@ -171,7 +173,7 @@ jenkins/Jenkinsfile.build-and-deploy
4. `CLEAR_DATABASE`
5. `MIGRATE_ON_CONFLICT`
6. `MIGRATION_DIRECTORY`
7. `DATABASE`:发布包默认数据库名,默认 `genarrative-pipeline-local-test`只能包含数字、字母、点和短横线
7. `DATABASE`:发布包默认数据库名,默认 `genarrative-pipeline-local-test`必须匹配 `^[a-z0-9]+(-[a-z0-9]+)*$`
如果你选择启用 `RUN_DEPLOY_HOOKS_WITH_SUDO=true`,推荐提前在服务器上增加一份最小 sudoers 配置,例如:

View File

@@ -90,7 +90,7 @@ Genarrative-Database-Import
`Genarrative-Build-And-Deploy` 增加以下本地发布包参数,便于在 Jenkins 中测试本地 SpacetimeDB不依赖 Maincloud
1. `DATABASE`:发布包默认数据库名,默认 `genarrative-pipeline-local-test`。SpacetimeDB CLI 当前只接受数字、字母、点和短横线,不要使用下划线。
1. `DATABASE`:发布包默认数据库名,默认 `genarrative-pipeline-local-test`。SpacetimeDB CLI 当前要求数据库名匹配 `^[a-z0-9]+(-[a-z0-9]+)*$`,只能使用小写字母、数字,并用单个短横线分隔;不要使用大写字母、点号、下划线、首尾短横线或连续短横线。
2. `API_PORT`:发布包内 api-server 端口,默认 `8082`
3. `WEB_PORT`:发布包内静态网站端口,默认 `25001`
4. `SPACETIME_PORT`:发布包内本地 SpacetimeDB 端口,默认 `3101`

View File

@@ -145,7 +145,9 @@ npm run deploy:rust:remote
8. 在目标目录写入 `start.sh``stop.sh``start.sh` 会先按 `KEY=value` 子集加载发布目录根部的 `.env``.env.local`,兼容 UTF-8 BOM 与 CRLF再回退到构建时通过 `--database``--api-port``--web-port``--spacetime-host``--spacetime-port` 写入的默认值,并默认导出 `NO_COLOR=1``CARGO_TERM_COLOR=never`,避免 ANSI 控制码写入日志文件;同时按 Ubuntu 发布环境使用发布目录内 `.spacetimedb/` 作为 root-dir不再额外设置 `--data-dir`,启动前先执行 `sync_ubuntu_spacetime_install`,优先从 `/usr/.local/share/spacetime/bin/<version>/spacetimedb-cli``$HOME/.local/share/spacetime/bin/<version>/spacetimedb-cli` 同步到 `.spacetimedb/bin/current/spacetimedb-cli`,当前线上 `spacetime` 入口为 `/usr/local/bin/spacetime`;启动参数为 `spacetime --root-dir ./.spacetimedb start --edition standalone --listen-addr <host>:<port>`,探活必须确认 `server ping` 输出包含 `Server is online:`;普通启动先无清库发布,若 publish 输出可判定为 schema 冲突,则自动导出旧库、清库发布新 wasm、导入回灌如果以 `--clear-database` 启动,则内部 `spacetime publish` 会追加 `-c=on-conflict`,代表人工确认清库,不触发自动回灌。
9. 默认执行 `scp -r -i ~\.ssh\dsk.pem build/<timestamp> ubuntu@82.157.175.59:/home/ubuntu/genarrative/` 上传发布包。
SpacetimeDB database 名称只能包含数字、字母、点和短横线;不要使用下划线,否则 `spacetime publish` 会报 `invalid characters in database name`。发布包构建脚本和 `start.sh` 都会提前拦截这类非法名称。
SpacetimeDB database 名称必须匹配 `^[a-z0-9]+(-[a-z0-9]+)*$`:只能使用小写字母、数字,并用单个短横线分隔;大写字母、点号、下划线、首尾短横线和连续短横线都会触发 `spacetime publish` `invalid characters in database name`。发布包构建脚本和 `start.sh` 都会提前拦截这类非法名称。
发布包构建日志会输出 `SpacetimeDB 发布数据库: <database>`;目标服务器执行 `start.sh` 时会在发布前输出最终加载后的 `database/server/root-dir`,用于确认 `.env.local` 或 Jenkins 参数覆盖后的实际发布目标。
发布包结构:

View File

@@ -32,7 +32,8 @@ npm run spacetime:publish:maincloud
1. 使用 `cargo build -p spacetime-module --target wasm32-unknown-unknown --release` 构建 wasm。
2. 使用 `spacetime publish <database> --server maincloud --bin-path <wasm> --yes` 发布到 Maincloud。
3. 输出 `api-server` 需要的 Maincloud 环境变量,便于部署进程复用
3. 发布前输出目标数据库名和 server便于在 Jenkins 或手工日志中确认实际发布目标
4. 输出 `api-server` 需要的 Maincloud 环境变量,便于部署进程复用。
如需 schema 冲突时清库发布:
@@ -56,6 +57,7 @@ npm run api-server:maincloud
## 设计约束
- Maincloud 数据库名必须显式配置,不能默认读取本地 `spacetime.local.json`
- Maincloud 数据库名必须匹配 `^[a-z0-9]+(-[a-z0-9]+)*$`,只能使用小写字母、数字,并用单个短横线分隔;否则 `spacetime publish` 会报 `invalid characters in database name`
- 发布脚本只处理 SpacetimeDB 模块发布,不启动本地 SpacetimeDB。
- `api-server` 继续通过 `SpacetimeClientConfig``server_url / database / token` 连接数据库,不在前端增加逻辑。
- Windows 进程清理只能匹配本仓库 `server-rs/target/debug/api-server.exe` 的完整路径,不能按进程名泛化清理,避免影响其他 Rust 服务。

View File

@@ -39,10 +39,11 @@ pipeline {
if (!database) {
error('DATABASE 不能为空。')
}
if (!(database ==~ /^[0-9A-Za-z.-]+$/)) {
error("DATABASE 只能包含数字、字母、点和短横线,不能包含下划线,当前值: ${database}")
if (!(database ==~ /^[a-z0-9]+(-[a-z0-9]+)*$/)) {
error("DATABASE 必须匹配 SpacetimeDB 数据库名规则 ^[a-z0-9]+(-[a-z0-9]+)*$,只能使用小写字母、数字,并用单个短横线分隔,当前值: ${database}")
}
env.EFFECTIVE_DATABASE = database
echo "SpacetimeDB 发布数据库: ${env.EFFECTIVE_DATABASE}"
def apiPort = params.API_PORT?.trim()
if (!apiPort) {
error('API_PORT 不能为空。')

View File

@@ -270,11 +270,13 @@ if [[ ! "${BUILD_NAME}" =~ ^[0-9A-Za-z._-]+$ ]]; then
exit 1
fi
if [[ ! "${DATABASE}" =~ ^[0-9A-Za-z.-]+$ ]]; then
echo "[deploy:rust] --database 只能包含数字、字母、点和短横线,不能包含下划线: ${DATABASE}" >&2
if [[ ! "${DATABASE}" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
echo "[deploy:rust] --database 必须匹配 SpacetimeDB 数据库名规则 ^[a-z0-9]+(-[a-z0-9]+)*$,只能使用小写字母、数字,并用单个短横线分隔: ${DATABASE}" >&2
exit 1
fi
echo "[deploy:rust] SpacetimeDB 发布数据库: ${DATABASE}"
if [[ "${SKIP_SPACETIME_BUILD}" -eq 1 && "${MIGRATION_BOOTSTRAP_SECRET_MODE}" != "disabled" ]]; then
echo "[deploy:rust] --skip-spacetime-build 无法把迁移引导密钥注入 wasm。" >&2
echo "[deploy:rust] 请移除 --skip-spacetime-build或同时传 --no-migration-bootstrap-secret。" >&2
@@ -662,8 +664,8 @@ sanitize_path_segment() {
validate_spacetime_database_name() {
local database="$1"
if [[ ! "${database}" =~ ^[0-9A-Za-z.-]+$ ]]; then
echo "[start] GENARRATIVE_SPACETIME_DATABASE 只能包含数字、字母、点和短横线,不能包含下划线: ${database}" >&2
if [[ ! "${database}" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
echo "[start] GENARRATIVE_SPACETIME_DATABASE 必须匹配 SpacetimeDB 数据库名规则 ^[a-z0-9]+(-[a-z0-9]+)*$,只能使用小写字母、数字,并用单个短横线分隔: ${database}" >&2
exit 1
fi
}
@@ -985,9 +987,15 @@ start_process() {
echo "$!" >"${pid_file}"
}
validate_spacetime_database_name "${SPACETIME_DATABASE}"
echo "[start] SpacetimeDB 发布配置:"
echo "[start] - database: ${SPACETIME_DATABASE}"
echo "[start] - server: ${SPACETIME_SERVER_URL}"
echo "[start] - root-dir: ${SPACETIME_ROOT_DIR}"
require_command node
require_command spacetime
validate_spacetime_database_name "${SPACETIME_DATABASE}"
mkdir -p "${PID_DIR}" "${LOG_DIR}" "${SPACETIME_ROOT_DIR}"
sync_ubuntu_spacetime_install "${SPACETIME_ROOT_DIR}"
@@ -1075,6 +1083,7 @@ echo "[start] 完成"
echo "[start] Web: http://${WEB_HOST}:${WEB_PORT}"
echo "[start] API: http://${API_HOST}:${API_PORT}"
echo "[start] SpacetimeDB: ${SPACETIME_SERVER_URL}"
echo "[start] SpacetimeDB database: ${SPACETIME_DATABASE}"
START_SCRIPT
replace_placeholder_in_file "${TARGET_DIR}/start.sh" "__GENARRATIVE_DEFAULT_SPACETIME_HOST__" "${SPACETIME_HOST}"

View File

@@ -85,6 +85,7 @@ export function buildSpacetimeCallArgs(options, procedureName, input) {
if (!options.database) {
throw new Error('必须传入 --database。');
}
validateSpacetimeDatabaseName(options.database);
const args = [];
if (options.rootDir) {
@@ -108,6 +109,7 @@ export async function callSpacetimeProcedure(options, procedureName, input) {
if (!options.database) {
throw new Error('必须传入 --database或设置 GENARRATIVE_SPACETIME_DATABASE。');
}
validateSpacetimeDatabaseName(options.database);
const serverUrl = resolveServerUrl(options).replace(/\/+$/u, '');
const url = `${serverUrl}/v1/database/${encodeURIComponent(options.database)}/call/${encodeURIComponent(procedureName)}`;
@@ -195,6 +197,14 @@ export async function callSpacetimeProcedureViaCli(options, procedureName, input
return parseProcedureResult(output);
}
export function validateSpacetimeDatabaseName(database) {
if (!/^[a-z0-9]+(-[a-z0-9]+)*$/u.test(database)) {
throw new Error(
`SpacetimeDB 数据库名必须匹配 ^[a-z0-9]+(-[a-z0-9]+)*$,只能使用小写字母、数字,并用单个短横线分隔: ${database}`,
);
}
}
export function parseProcedureResult(output) {
const candidates = [];
const trimmed = output.trim();

View File

@@ -88,6 +88,15 @@ timestamp_slug() {
node -e 'process.stdout.write(new Date().toISOString().replace(/[:.]/g, "-"));'
}
validate_spacetime_database_name() {
local database="$1"
if [[ ! "${database}" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
echo "[spacetime:maincloud] --database 必须匹配 SpacetimeDB 数据库名规则 ^[a-z0-9]+(-[a-z0-9]+)*$,只能使用小写字母、数字,并用单个短横线分隔: ${database}" >&2
exit 1
fi
}
is_publish_conflict_output() {
local output="$1"
[[ "${output}" == *"conflict"* ]] \
@@ -209,6 +218,11 @@ if [[ -z "${SPACETIME_DATABASE}" ]]; then
exit 1
fi
validate_spacetime_database_name "${SPACETIME_DATABASE}"
echo "[spacetime:maincloud] SpacetimeDB 发布数据库: ${SPACETIME_DATABASE}"
echo "[spacetime:maincloud] SpacetimeDB server: ${SPACETIME_SERVER_ALIAS} (${SPACETIME_SERVER_URL})"
if ! command -v cargo >/dev/null 2>&1; then
echo "[spacetime:maincloud] 缺少 cargo 命令。" >&2
exit 1