更新 devlop 脚本以统一端口配置,优化项目结构;修正合并脚本中的路径引用,确保正确合并 newapp 构建产物至 miniprogram 目录。

This commit is contained in:
乘风
2026-02-03 16:27:02 +08:00
parent a2443c097c
commit 0a57872f24
3 changed files with 58 additions and 52 deletions

View File

@@ -4,8 +4,8 @@
Soul 创业派对 - 统一部署脚本(支持两种模式)
模式一 devlop默认dist 切换方式
本地 pnpm build → 打包 zip → 上传解压到 dist2 → 宝塔暂停 → dist→dist1, dist2→dist → 重启
用法: python scripts/devlop.py [--no-build]
本地 pnpm build → 打包 zip → 上传解压到 dist2 → 在 dist2 执行 pnpm install 并等待完成 → 再切换目录、重启
用法: python scripts/TestDevlop.py [--no-build]
模式二 deploy直接覆盖方式
本地打包 tar.gz → SSH 上传解压到项目目录 → 宝塔 API 重启
@@ -16,7 +16,8 @@ Soul 创业派对 - 统一部署脚本(支持两种模式)
DEPLOY_PROJECT_PATH # deploy 模式项目路径,默认 /www/wwwroot/soulTest
DEVOP_BASE_PATH # devlop 模式目录,默认 /www/wwwroot/auto-devlop/soulTest
BAOTA_PANEL_URL / BAOTA_API_KEY / DEPLOY_PM2_APP
DEPLOY_PORT / DEPLOY_NODE_VERSION / DEPLOY_NODE_PATH
DEPLOY_PORT # 应用端口,统一由此读取,默认 30066见 DEFAULT_DEPLOY_PORT
DEPLOY_NODE_VERSION / DEPLOY_NODE_PATH
"""
from __future__ import print_function
@@ -52,6 +53,12 @@ except ImportError:
# ==================== 配置 ====================
# 端口统一从环境变量 DEPLOY_PORT 读取,未设置时使用此默认值
DEPLOY_PM2_APP = "testsoul"
DEFAULT_DEPLOY_PORT = 30066
DEPLOY_PROJECT_PATH = "/www/wwwroot/soulTest"
DEPLOY_SITE_URL = "https://soulTest.quwanzhi.com"
def get_cfg():
"""获取基础部署配置deploy 模式与 devlop 共用 SSH/宝塔)"""
return {
@@ -59,12 +66,12 @@ def get_cfg():
"user": os.environ.get("DEPLOY_USER", "root"),
"password": os.environ.get("DEPLOY_PASSWORD", "Zhiqun1984"),
"ssh_key": os.environ.get("DEPLOY_SSH_KEY", ""),
"project_path": os.environ.get("DEPLOY_PROJECT_PATH", "/www/wwwroot/soulTest"),
"project_path": os.environ.get("DEPLOY_PROJECT_PATH", DEPLOY_PROJECT_PATH),
"panel_url": os.environ.get("BAOTA_PANEL_URL", "https://42.194.232.22:9988"),
"api_key": os.environ.get("BAOTA_API_KEY", "hsAWqFSi0GOCrunhmYdkxy92tBXfqYjd"),
"pm2_name": os.environ.get("DEPLOY_PM2_APP", "soulTest"),
"site_url": os.environ.get("DEPLOY_SITE_URL", "https://soulTest.quwanzhi.com"),
"port": int(os.environ.get("DEPLOY_PORT", "30066")),
"pm2_name": os.environ.get("DEPLOY_PM2_APP", DEPLOY_PM2_APP),
"site_url": os.environ.get("DEPLOY_SITE_URL", DEPLOY_SITE_URL),
"port": int(os.environ.get("DEPLOY_PORT", str(DEFAULT_DEPLOY_PORT))),
"node_version": os.environ.get("DEPLOY_NODE_VERSION", "v22.14.0"),
"node_path": os.environ.get("DEPLOY_NODE_PATH", "/www/server/nodejs/v22.14.0/bin"),
}
@@ -152,7 +159,9 @@ def restart_node_project(panel_url, api_key, pm2_name):
return False
def add_or_update_node_project(panel_url, api_key, pm2_name, project_path, port=30006, node_path=None):
def add_or_update_node_project(panel_url, api_key, pm2_name, project_path, port=None, node_path=None):
if port is None:
port = int(os.environ.get("DEPLOY_PORT", str(DEFAULT_DEPLOY_PORT)))
port_env = "PORT=%d " % port
run_cmd = port_env + ("%s/node server.js" % node_path if node_path else "node server.js")
payload = {"name": pm2_name, "path": project_path, "run_cmd": run_cmd, "port": str(port)}
@@ -402,7 +411,7 @@ def deploy_via_baota_api(cfg):
panel_url, api_key, pm2_name = cfg["panel_url"], cfg["api_key"], cfg["pm2_name"]
project_path = cfg["project_path"]
node_path = cfg.get("node_path", "/www/server/nodejs/v22.14.0/bin")
port = cfg.get("port", 30006)
port = cfg["port"]
if not get_node_project_status(panel_url, api_key, pm2_name):
add_or_update_node_project(panel_url, api_key, pm2_name, project_path, port, node_path)
@@ -482,11 +491,12 @@ def pack_standalone_zip(root):
server_js = os.path.join(staging, "server.js")
if os.path.isfile(server_js):
try:
deploy_port = int(os.environ.get("DEPLOY_PORT", str(DEFAULT_DEPLOY_PORT)))
with open(server_js, "r", encoding="utf-8") as f:
c = f.read()
if "|| 3000" in c:
with open(server_js, "w", encoding="utf-8") as f:
f.write(c.replace("|| 3000", "|| 30006"))
f.write(c.replace("|| 3000", "|| %d" % deploy_port))
except Exception:
pass
zip_path = os.path.join(tempfile.gettempdir(), "soul_devlop.zip")
@@ -577,8 +587,9 @@ def upload_zip_and_extract_to_dist2(cfg, zip_path):
def run_pnpm_install_in_dist2(cfg):
"""服务器 dist2 内执行 pnpm installdevlop 模式"""
print("[4/7] 服务器 dist2 内执行 pnpm install ...")
"""服务器 dist2 内执行 pnpm install,阻塞等待完成后再返回(改目录前必须完成"""
print("[4/7] 服务器 dist2 内执行 pnpm install(等待完成后再切换目录)...")
sys.stdout.flush()
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
@@ -596,7 +607,7 @@ def run_pnpm_install_in_dist2(cfg):
err = stderr.read().decode("utf-8", errors="replace").strip()
if stdout.channel.recv_exit_status() != 0:
return False, "pnpm install 失败\n" + (err or out)
print(" [成功] pnpm install 完成")
print(" [成功] dist2 内 pnpm install 已执行完成,可安全切换目录")
return True, None
except Exception as e:
return False, str(e)
@@ -673,10 +684,12 @@ def main():
os.remove(zip_path)
except Exception:
pass
# 必须在 dist2 内 pnpm install 执行完成后再切换目录
ok, err = run_pnpm_install_in_dist2(cfg)
if not ok:
print(" [失败] %s" % (err or "pnpm install 失败"))
return 1
# install 已完成,再执行 dist→dist1、dist2→dist 切换
if not remote_swap_dist_and_restart(cfg):
return 1
print("")

View File

@@ -1,23 +1,5 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Soul 创业派对 - 统一部署脚本(支持两种模式)
模式一 devlop默认dist 切换方式
本地 pnpm build → 打包 zip → 上传解压到 dist2 → 宝塔暂停 → dist→dist1, dist2→dist → 重启
用法: python scripts/devlop.py [--no-build]
模式二 deploy直接覆盖方式
本地打包 tar.gz → SSH 上传解压到项目目录 → 宝塔 API 重启
用法: python scripts/devlop.py --mode deploy [--no-build] [--no-upload] [--no-api]
环境变量(可选):
DEPLOY_HOST / DEPLOY_USER / DEPLOY_PASSWORD / DEPLOY_SSH_KEY
DEPLOY_PROJECT_PATH # deploy 模式项目路径,默认 /www/wwwroot/soul
DEVOP_BASE_PATH # devlop 模式目录,默认 /www/wwwroot/auto-devlop/soul
BAOTA_PANEL_URL / BAOTA_API_KEY / DEPLOY_PM2_APP
DEPLOY_PORT / DEPLOY_NODE_VERSION / DEPLOY_NODE_PATH
"""
from __future__ import print_function
@@ -52,6 +34,12 @@ except ImportError:
# ==================== 配置 ====================
# 端口统一从环境变量 DEPLOY_PORT 读取,未设置时使用此默认值
DEPLOY_PM2_APP = "soul"
DEFAULT_DEPLOY_PORT = 30006
DEPLOY_PROJECT_PATH = "/www/wwwroot/soul"
DEPLOY_SITE_URL = "https://soul.quwanzhi.com"
def get_cfg():
"""获取基础部署配置deploy 模式与 devlop 共用 SSH/宝塔)"""
return {
@@ -59,12 +47,12 @@ def get_cfg():
"user": os.environ.get("DEPLOY_USER", "root"),
"password": os.environ.get("DEPLOY_PASSWORD", "Zhiqun1984"),
"ssh_key": os.environ.get("DEPLOY_SSH_KEY", ""),
"project_path": os.environ.get("DEPLOY_PROJECT_PATH", "/www/wwwroot/soul"),
"project_path": os.environ.get("DEPLOY_PROJECT_PATH", DEPLOY_PROJECT_PATH),
"panel_url": os.environ.get("BAOTA_PANEL_URL", "https://42.194.232.22:9988"),
"api_key": os.environ.get("BAOTA_API_KEY", "hsAWqFSi0GOCrunhmYdkxy92tBXfqYjd"),
"pm2_name": os.environ.get("DEPLOY_PM2_APP", "soul"),
"site_url": os.environ.get("DEPLOY_SITE_URL", "https://soul.quwanzhi.com"),
"port": int(os.environ.get("DEPLOY_PORT", "30006")),
"pm2_name": os.environ.get("DEPLOY_PM2_APP", DEPLOY_PM2_APP),
"site_url": os.environ.get("DEPLOY_SITE_URL", DEPLOY_SITE_URL),
"port": int(os.environ.get("DEPLOY_PORT", str(DEFAULT_DEPLOY_PORT))),
"node_version": os.environ.get("DEPLOY_NODE_VERSION", "v22.14.0"),
"node_path": os.environ.get("DEPLOY_NODE_PATH", "/www/server/nodejs/v22.14.0/bin"),
}
@@ -73,7 +61,7 @@ def get_cfg():
def get_cfg_devlop():
"""devlop 模式配置:在基础配置上增加 base_path / dist / dist2"""
cfg = get_cfg().copy()
cfg["base_path"] = os.environ.get("DEVOP_BASE_PATH", "/www/wwwroot/auto-devlop/soul")
cfg["base_path"] = os.environ.get("DEVOP_BASE_PATH", "/www/wwwroot/auto-devlop/soulTest")
cfg["dist_path"] = cfg["base_path"] + "/dist"
cfg["dist2_path"] = cfg["base_path"] + "/dist2"
return cfg
@@ -152,7 +140,9 @@ def restart_node_project(panel_url, api_key, pm2_name):
return False
def add_or_update_node_project(panel_url, api_key, pm2_name, project_path, port=30006, node_path=None):
def add_or_update_node_project(panel_url, api_key, pm2_name, project_path, port=None, node_path=None):
if port is None:
port = int(os.environ.get("DEPLOY_PORT", str(DEFAULT_DEPLOY_PORT)))
port_env = "PORT=%d " % port
run_cmd = port_env + ("%s/node server.js" % node_path if node_path else "node server.js")
payload = {"name": pm2_name, "path": project_path, "run_cmd": run_cmd, "port": str(port)}
@@ -364,8 +354,8 @@ def upload_and_extract(cfg, tarball_path):
else:
client.connect(cfg["host"], username=cfg["user"], password=cfg["password"], timeout=15)
sftp = client.open_sftp()
remote_tar = "/tmp/soul_deploy.tar.gz"
remote_script = "/tmp/soul_deploy_extract.sh"
remote_tar = "/tmp/soulTest_deploy.tar.gz"
remote_script = "/tmp/soulTest_deploy_extract.sh"
sftp.put(tarball_path, remote_tar)
node_path = cfg.get("node_path", "/www/server/nodejs/v22.14.0/bin")
project_path = cfg["project_path"]
@@ -402,7 +392,7 @@ def deploy_via_baota_api(cfg):
panel_url, api_key, pm2_name = cfg["panel_url"], cfg["api_key"], cfg["pm2_name"]
project_path = cfg["project_path"]
node_path = cfg.get("node_path", "/www/server/nodejs/v22.14.0/bin")
port = cfg.get("port", 30006)
port = cfg["port"]
if not get_node_project_status(panel_url, api_key, pm2_name):
add_or_update_node_project(panel_url, api_key, pm2_name, project_path, port, node_path)
@@ -482,11 +472,12 @@ def pack_standalone_zip(root):
server_js = os.path.join(staging, "server.js")
if os.path.isfile(server_js):
try:
deploy_port = int(os.environ.get("DEPLOY_PORT", str(DEFAULT_DEPLOY_PORT)))
with open(server_js, "r", encoding="utf-8") as f:
c = f.read()
if "|| 3000" in c:
with open(server_js, "w", encoding="utf-8") as f:
f.write(c.replace("|| 3000", "|| 30006"))
f.write(c.replace("|| 3000", "|| %d" % deploy_port))
except Exception:
pass
zip_path = os.path.join(tempfile.gettempdir(), "soul_devlop.zip")
@@ -532,7 +523,7 @@ def upload_zip_and_extract_to_dist2(cfg, zip_path):
client.connect(cfg["host"], username=cfg["user"], password=cfg["password"], timeout=30, banner_timeout=30)
print(" [OK] SSH 已连接,正在上传 zip%.1f MB..." % zip_size_mb)
sys.stdout.flush()
remote_zip = cfg["base_path"].rstrip("/") + "/soul_devlop.zip"
remote_zip = cfg["base_path"].rstrip("/") + "/soulTest_devlop.zip"
sftp = client.open_sftp()
# 上传进度:每 5MB 打印一次
chunk_mb = 5.0
@@ -577,8 +568,9 @@ def upload_zip_and_extract_to_dist2(cfg, zip_path):
def run_pnpm_install_in_dist2(cfg):
"""服务器 dist2 内执行 pnpm installdevlop 模式"""
print("[4/7] 服务器 dist2 内执行 pnpm install ...")
"""服务器 dist2 内执行 pnpm install,阻塞等待完成后再返回(改目录前必须完成"""
print("[4/7] 服务器 dist2 内执行 pnpm install(等待完成后再切换目录)...")
sys.stdout.flush()
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
@@ -596,7 +588,7 @@ def run_pnpm_install_in_dist2(cfg):
err = stderr.read().decode("utf-8", errors="replace").strip()
if stdout.channel.recv_exit_status() != 0:
return False, "pnpm install 失败\n" + (err or out)
print(" [成功] pnpm install 完成")
print(" [成功] dist2 内 pnpm install 已执行完成,可安全切换目录")
return True, None
except Exception as e:
return False, str(e)
@@ -673,10 +665,12 @@ def main():
os.remove(zip_path)
except Exception:
pass
# 必须在 dist2 内 pnpm install 执行完成后再切换目录
ok, err = run_pnpm_install_in_dist2(cfg)
if not ok:
print(" [失败] %s" % (err or "pnpm install 失败"))
return 1
# install 已完成,再执行 dist→dist1、dist2→dist 切换
if not remote_swap_dist_and_restart(cfg):
return 1
print("")

View File

@@ -1,17 +1,17 @@
/**
* 将 newpp 构建产物 dist/mp 合并到项目根 miniprogram/
* 保留 miniprogram 壳custom-tab-bar、project.config.json、sitemap.json、app.js 的 globalData/request 等需手动合并
* 将 newapp 构建产物 dist/mp 合并到项目根 miniprogram/
* 保留 miniprogram 壳custom-tab-bar、project.config.json、sitemap.json、app.js(不覆盖壳的 app.js
* 用法node scripts/merge-kbone-to-miniprogram.js
*/
const fs = require('fs')
const path = require('path')
const root = path.resolve(__dirname, '..')
const distMp = path.join(root, 'newpp', 'dist', 'mp')
const distMp = path.join(root, 'newapp', 'dist', 'mp')
const miniprogram = path.join(root, 'miniprogram')
if (!fs.existsSync(distMp)) {
console.error('未找到 newpp/dist/mp请先在 newpp 目录执行: npm run build:mp')
console.error('未找到 newapp/dist/mp请先在 newapp 目录执行: npm run build:mp')
process.exit(1)
}
if (!fs.existsSync(miniprogram)) {
@@ -34,7 +34,7 @@ function copyDir(src, dest) {
}
// 要保留的 miniprogram 文件/目录(合并前备份,合并后覆盖回去)
const keep = ['custom-tab-bar', 'project.config.json', 'sitemap.json']
const keep = ['custom-tab-bar', 'project.config.json', 'sitemap.json', 'app.js']
const backupDir = path.join(root, '.miniprogram-backup')
if (!fs.existsSync(backupDir)) fs.mkdirSync(backupDir, { recursive: true })
@@ -82,5 +82,4 @@ for (const name of keep) {
}
}
console.log('已合并 newpp/dist/mp -> miniprogram/,并保留 custom-tab-bar、project.config.json、sitemap.json')
console.log('请手动合并 app.js 的 globalData、request、loadFeatureConfig 等逻辑到 kbone 生成的 app.js')
console.log('已合并 newapp/dist/mp -> miniprogram/,并保留 custom-tab-bar、project.config.json、sitemap.json、app.js')