fix(release): 修复发布包缺失 storage 模块,并加入产物完整性校验
用户实测:用发布包部署后启动报 MODULE_NOT_FOUND
at dist/models/models.module.js:13 require('../storage/storage.module')
根因:package-release.sh 的 rsync 用了 --exclude 'storage'。该模式匹配
**任意层级**的同名目录,把源码目录 src/storage/ 与编译产物 dist/storage/
一并排除——发布包里完全没有 storage 模块,服务必然起不来。
这与第一阶段 .gitignore 里 'storage/' 误伤 src/storage/ 是同一类错误,
本项目第二次踩到。
修复:
- 排除模式全部锚定到 web-server 根:'/storage/'、'/data/'、'/tmp/'、
'/.env'、'/admin/',不再匹配嵌套同名目录
- 新增产物完整性校验(打包后自动执行,失败即删除压缩包):
src 下每个 .ts 必须有对应 dist/*.js;关键文件清单齐全;
不得混入 node_modules / 真实 .env / 运行时存储 / keystore
- ctl.sh 补上缺失的 warn 函数(line 120: warn: command not found)
实测:
- 对照实验:排除模式改回 'storage' 后校验准确报出缺少
dist/storage/storage.module.js 并删除压缩包,退出码 1
- 新包端到端:解压 → npm ci --omit=dev(213 包)→ 启动 → /health 200、
MariaDB 已连接、迁移 0、catalog/songs/models/motions 全部 200
This commit is contained in:
@@ -47,13 +47,19 @@ rm -rf "$STAGE"
|
||||
mkdir -p "$STAGE"
|
||||
|
||||
# 后端源码 + 构建产物(排除依赖、测试、存储、密钥)
|
||||
# 排除模式**必须锚定到 web-server 根目录**(前导 /)。
|
||||
# 否则 rsync 的 'storage' 会匹配任意层级的同名目录,把源码目录
|
||||
# src/storage/ 与编译产物 dist/storage/ 一并删掉——发布包会缺少整个
|
||||
# storage 模块,服务启动即 MODULE_NOT_FOUND。这是本项目第二次踩到
|
||||
# 「storage 误伤源码目录」这个坑(第一次是 .gitignore)。
|
||||
rsync -a --delete \
|
||||
--exclude 'node_modules' \
|
||||
--exclude 'storage' \
|
||||
--exclude 'data' \
|
||||
--exclude '.env' \
|
||||
--exclude '.env.local' \
|
||||
--exclude 'admin' \
|
||||
--exclude '/storage/' \
|
||||
--exclude '/data/' \
|
||||
--exclude '/tmp/' \
|
||||
--exclude '/.env' \
|
||||
--exclude '/.env.local' \
|
||||
--exclude '/admin/' \
|
||||
web-server/ "$STAGE/web-server/"
|
||||
|
||||
# 管理端构建产物(文档要求 admin/ 与 web-server/ 平级)
|
||||
@@ -77,6 +83,67 @@ cp -r tasks "$STAGE/tasks"
|
||||
log "生成压缩包..."
|
||||
( cd "$OUT_DIR" && tar -czf "$NAME.tar.gz" "$NAME" )
|
||||
|
||||
# ---------- 6. 产物完整性校验 ----------
|
||||
# 打包脚本本身的错误(如排除模式写错)会静默产出残缺的发布包,
|
||||
# 直到目标机启动时才暴露。这里做一次硬校验:src 下每个 .ts 都必须在
|
||||
# 包内有对应的 dist/*.js,且关键文件齐全。
|
||||
log "校验产物完整性…"
|
||||
MANIFEST_TMP=$(tar -tzf "$OUT_DIR/$NAME.tar.gz")
|
||||
|
||||
fail=0
|
||||
|
||||
# 6.1 src → dist 一一对应(能抓到整目录被误排除这类问题)
|
||||
# 注意 nest build 的 sourceRoot 是 src,产物会**去掉 src/ 前缀**:
|
||||
# web-server/src/storage/storage.service.ts → web-server/dist/storage/storage.service.js
|
||||
while IFS= read -r tsfile; do
|
||||
rel="${tsfile#src/}"
|
||||
jsfile="opendance-web-v${VERSION}/web-server/dist/${rel%.ts}.js"
|
||||
if ! grep -qx "$jsfile" <<< "$MANIFEST_TMP"; then
|
||||
echo " ✗ 缺少编译产物:$jsfile(源:$tsfile)" >&2
|
||||
fail=1
|
||||
fi
|
||||
done < <(cd web-server && find src -name '*.ts' ! -name '*.spec.ts')
|
||||
[ "$fail" -eq 0 ] && echo " ✓ src 下所有 .ts 均有对应 dist/*.js"
|
||||
|
||||
# 6.2 关键文件
|
||||
for required in \
|
||||
"opendance-web-v${VERSION}/web-server/dist/main.js" \
|
||||
"opendance-web-v${VERSION}/web-server/src/storage/storage.service.ts" \
|
||||
"opendance-web-v${VERSION}/admin/index.html" \
|
||||
"opendance-web-v${VERSION}/deploy/install.sh" \
|
||||
"opendance-web-v${VERSION}/deploy/ctl.sh" \
|
||||
"opendance-web-v${VERSION}/deploy/nginx/opendance.conf" \
|
||||
"opendance-web-v${VERSION}/deploy/systemd/opendance-api.service" \
|
||||
"opendance-web-v${VERSION}/contracts/VERSION" \
|
||||
"opendance-web-v${VERSION}/THIRD_PARTY.md" \
|
||||
"opendance-web-v${VERSION}/README.txt" ; do
|
||||
if ! grep -qx "$required" <<< "$MANIFEST_TMP"; then
|
||||
echo " ✗ 缺少关键文件:$required" >&2
|
||||
fail=1
|
||||
fi
|
||||
done
|
||||
|
||||
# 6.3 不得包含的东西(模式必须精确,否则会误伤 src/storage、.env.example)
|
||||
PREFIX="opendance-web-v${VERSION}"
|
||||
check_forbidden() {
|
||||
local label="$1" pattern="$2"
|
||||
if grep -qE "$pattern" <<< "$MANIFEST_TMP"; then
|
||||
echo " ✗ 产物中混入了不应包含的内容($label)" >&2
|
||||
grep -E "$pattern" <<< "$MANIFEST_TMP" | head -3 | sed 's/^/ /' >&2
|
||||
fail=1
|
||||
fi
|
||||
}
|
||||
check_forbidden "node_modules" "node_modules"
|
||||
check_forbidden "真实 .env" "^${PREFIX}/(deploy|web-server)/\.env$"
|
||||
check_forbidden "运行时存储目录" "^${PREFIX}/web-server/storage/"
|
||||
check_forbidden "keystore" "\.jks$|keystore\.properties$"
|
||||
[ "$fail" -eq 0 ] && echo " ✓ 无 node_modules / 真实 .env / 运行时存储 / keystore"
|
||||
|
||||
if [ "$fail" -ne 0 ]; then
|
||||
rm -f "$OUT_DIR/$NAME.tar.gz"
|
||||
die "产物完整性校验失败,已删除有问题的压缩包"
|
||||
fi
|
||||
|
||||
log "完成:$OUT_DIR/$NAME.tar.gz"
|
||||
echo
|
||||
echo "产物内容:"
|
||||
|
||||
Reference in New Issue
Block a user