This commit is contained in:
乘风
2026-02-05 11:35:57 +08:00
parent 8c2a6391af
commit b96acadf91
31 changed files with 2263 additions and 4933 deletions

View File

@@ -36,7 +36,7 @@ except ImportError:
# 端口统一从环境变量 DEPLOY_PORT 读取,未设置时使用此默认值
DEPLOY_PM2_APP = "soul"
DEFAULT_DEPLOY_PORT = 30006
DEFAULT_DEPLOY_PORT = 3888
DEPLOY_PROJECT_PATH = "/www/wwwroot/soul"
DEPLOY_SITE_URL = "https://soul.quwanzhi.com"
# SSH 端口(支持环境变量 DEPLOY_SSH_PORT未设置时默认为 22022
@@ -61,7 +61,9 @@ def get_cfg():
def get_cfg_devlop():
"""devlop 模式配置:在基础配置上增加 base_path / dist / dist2"""
"""devlop 模式配置:在基础配置上增加 base_path / dist / dist2
实际运行目录为 dist_path切换后新版本在 dist宝塔 PM2 项目路径必须指向 dist_path
否则会从错误目录启动导致 .next/static 等静态资源 404。"""
cfg = get_cfg().copy()
cfg["base_path"] = os.environ.get("DEVOP_BASE_PATH", "/www/wwwroot/auto-devlop/soul")
cfg["dist_path"] = cfg["base_path"] + "/dist"
@@ -269,6 +271,10 @@ def pack_standalone_tar(root):
if not os.path.isdir(standalone) or not os.path.isdir(static_src):
print(" [失败] 未找到 .next/standalone 或 .next/static")
return None
chunks_dir = os.path.join(static_src, "chunks")
if not os.path.isdir(chunks_dir):
print(" [失败] .next/static/chunks 不存在,请先完整执行 pnpm build本地 pnpm start 能正常打开页面后再部署)")
return None
staging = tempfile.mkdtemp(prefix="soul_deploy_")
try:
@@ -291,6 +297,13 @@ def pack_standalone_tar(root):
shutil.rmtree(static_dst)
os.makedirs(os.path.dirname(static_dst), exist_ok=True)
shutil.copytree(static_src, static_dst)
# 同步构建索引,避免 server 用错 BUILD_ID/manifest 导致静态 404
next_root = os.path.join(root, ".next")
next_staging = os.path.join(staging, ".next")
for name in ["BUILD_ID", "build-manifest.json", "app-path-routes-manifest.json", "routes-manifest.json"]:
src = os.path.join(next_root, name)
if os.path.isfile(src):
shutil.copy2(src, os.path.join(next_staging, name))
if os.path.isdir(public_src):
shutil.copytree(public_src, os.path.join(staging, "public"), dirs_exist_ok=True)
if os.path.isfile(ecosystem_src):
@@ -410,7 +423,7 @@ def deploy_via_baota_api(cfg):
# ==================== 打包devlop 模式zip ====================
ZIP_EXCLUDE_DIRS = {".cache", "__pycache__", ".git", "node_modules", "cache", "test", "tests", "coverage", ".nyc_output", ".turbo", "开发文档", "miniprogramPre", "my-app", "newpp"}
ZIP_EXCLUDE_DIRS = {".cache", "__pycache__", ".git", "node_modules", "cache", "test", "tests", "coverage", ".nyc_output", ".turbo", "开发文档"}
ZIP_EXCLUDE_FILE_NAMES = {".DS_Store", "Thumbs.db"}
ZIP_EXCLUDE_FILE_SUFFIXES = (".log", ".map")
@@ -438,6 +451,10 @@ def pack_standalone_zip(root):
if not os.path.isdir(standalone) or not os.path.isdir(static_src):
print(" [失败] 未找到 .next/standalone 或 .next/static")
return None
chunks_dir = os.path.join(static_src, "chunks")
if not os.path.isdir(chunks_dir):
print(" [失败] .next/static/chunks 不存在,请先完整执行 pnpm build本地 pnpm start 能正常打开页面后再部署)")
return None
staging = tempfile.mkdtemp(prefix="soul_devlop_")
try:
@@ -457,6 +474,13 @@ def pack_standalone_zip(root):
break
os.makedirs(os.path.join(staging, ".next"), exist_ok=True)
shutil.copytree(static_src, os.path.join(staging, ".next", "static"), dirs_exist_ok=True)
# 同步构建索引,避免 server 用错 BUILD_ID/manifest 导致静态 404
next_root = os.path.join(root, ".next")
next_staging = os.path.join(staging, ".next")
for name in ["BUILD_ID", "build-manifest.json", "app-path-routes-manifest.json", "routes-manifest.json"]:
src = os.path.join(next_root, name)
if os.path.isfile(src):
shutil.copy2(src, os.path.join(next_staging, name))
if os.path.isdir(public_src):
shutil.copytree(public_src, os.path.join(staging, "public"), dirs_exist_ok=True)
if os.path.isfile(ecosystem_src):
@@ -599,7 +623,7 @@ def run_pnpm_install_in_dist2(cfg):
def remote_swap_dist_and_restart(cfg):
"""暂停 → dist→dist1, dist2→dist → 删除 dist1 → 重启devlop 模式)"""
"""暂停 → dist→dist1, dist2→dist → 删除 dist1 → 更新 PM2 项目路径 → 重启devlop 模式)"""
print("[5/7] 宝塔 API 暂停 Node 项目 ...")
stop_node_project(cfg["panel_url"], cfg["api_key"], cfg["pm2_name"])
time.sleep(2)
@@ -620,9 +644,16 @@ def remote_swap_dist_and_restart(cfg):
print(" [成功] 新版本位于 %s" % cfg["dist_path"])
finally:
client.close()
print("[7/7] 宝塔 API 重启 Node 项目 ...")
# 关键devlop 实际运行目录是 dist_path必须让宝塔 PM2 从该目录启动,否则会从错误目录跑导致静态资源 404
print("[7/7] 更新宝塔 Node 项目路径并重启 ...")
add_or_update_node_project(
cfg["panel_url"], cfg["api_key"], cfg["pm2_name"],
cfg["dist_path"], # 使用 dist_path不是 project_path
port=cfg["port"],
node_path=cfg.get("node_path"),
)
if not start_node_project(cfg["panel_url"], cfg["api_key"], cfg["pm2_name"]):
print(" [警告] 请到宝塔手动启动 %s" % cfg["pm2_name"])
print(" [警告] 请到宝塔手动启动 %s,并确认项目路径为: %s" % (cfg["pm2_name"], cfg["dist_path"]))
return False
return True