#!/usr/bin/env node /** * @file /scripts/publish.mjs * @description 构建后生成 update.json 并上传到远程服务器 * @usage node scripts/publish.mjs [--notes "更新说明"] * * 前置条件: * 1. 已运行 `pnpm run tauri-build` 生成构建产物 * 2. 远程服务器 SSH 可达(192.168.2.127:22) */ import { readFileSync, writeFileSync, readdirSync, existsSync } from "node:fs"; import { resolve, dirname, basename } from "node:path"; import { fileURLToPath } from "node:url"; import { execSync } from "node:child_process"; const __dirname = dirname(fileURLToPath(import.meta.url)); const root = resolve(__dirname, ".."); // ===== 配置 ===== const REMOTE_USER = "root_test"; const REMOTE_HOST = "192.168.2.127"; const REMOTE_PORT = 22; const REMOTE_DIR = "/var/www/html/work-order-monitor"; const BASE_URL = "http://web.nps.yunvip123.cn/work-order-monitor"; // ===== 解析参数 ===== const args = process.argv.slice(2); let notes = ""; const notesIdx = args.indexOf("--notes"); if (notesIdx !== -1 && args[notesIdx + 1]) { notes = args[notesIdx + 1]; } // ===== 读取版本号 ===== const pkg = JSON.parse(readFileSync(resolve(root, "package.json"), "utf-8")); const version = pkg.version; // ===== 查找构建产物 ===== const bundleDir = resolve(root, "src-tauri/target/release/bundle/nsis"); if (!existsSync(bundleDir)) { console.error(`错误: 未找到构建目录 ${bundleDir}`); console.error("请先运行: pnpm run tauri-build"); process.exit(1); } const files = readdirSync(bundleDir); const setupFile = files.find((f) => f.includes(version) && f.endsWith("-setup.exe")); const sigFile = files.find((f) => f.includes(version) && f.endsWith("-setup.exe.sig")); if (!setupFile || !sigFile) { console.error(`错误: 未找到版本 ${version} 的 -setup.exe 或 -setup.exe.sig 文件`); console.error(`目录内容: ${files.join(", ")}`); process.exit(1); } const setupPath = resolve(bundleDir, setupFile); const sigPath = resolve(bundleDir, sigFile); const signature = readFileSync(sigPath, "utf-8").trim(); console.log(`\n版本: ${version}`); console.log(`安装包: ${setupFile}`); console.log(`签名文件: ${sigFile}`); console.log(`签名: ${signature.substring(0, 40)}...`); // ===== 生成 update.json ===== const encodedFileName = encodeURIComponent(setupFile); const updateJson = { version, notes: notes || `v${version} 更新`, pub_date: new Date().toISOString(), platforms: { "windows-x86_64": { url: `${BASE_URL}/${encodedFileName}`, signature, }, }, }; const updateJsonPath = resolve(bundleDir, "update.json"); writeFileSync(updateJsonPath, JSON.stringify(updateJson, null, 2), "utf-8"); console.log(`\nupdate.json 已生成`); console.log(JSON.stringify(updateJson, null, 2)); // ===== 上传到远程服务器 ===== console.log(`\n正在上传到 ${REMOTE_HOST}:${REMOTE_DIR} ...`); try { // 确保远程目录存在 execSync( `ssh -p ${REMOTE_PORT} ${REMOTE_USER}@${REMOTE_HOST} "mkdir -p ${REMOTE_DIR}"`, { stdio: "inherit" } ); // 上传安装包 console.log(` 上传 ${setupFile} ...`); execSync( `scp -P ${REMOTE_PORT} "${setupPath}" ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}/`, { stdio: "inherit" } ); // 上传 update.json console.log(` 上传 update.json ...`); execSync( `scp -P ${REMOTE_PORT} "${updateJsonPath}" ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}/`, { stdio: "inherit" } ); console.log("\n全部上传完成!"); console.log(`更新地址: ${BASE_URL}/update.json`); console.log(`下载地址: ${BASE_URL}/${encodedFileName}\n`); } catch (e) { console.error("\n上传失败:", e.message); console.error("请检查 SSH 连接是否正常,或手动上传以下文件:"); console.error(` 1. ${setupPath}`); console.error(` 2. ${updateJsonPath}`); console.error(` → 目标: ${REMOTE_HOST}:${REMOTE_DIR}/`); process.exit(1); }