feat(): 添加更新功能

This commit is contained in:
tsl
2026-03-25 10:06:25 +08:00
parent 92055dd6a0
commit 1b6e12e402
23 changed files with 1045 additions and 285 deletions
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env node
/**
* 构建脚本 - 自动加载项目内置签名密钥后执行 tauri build
*/
import { readFileSync } from "node:fs";
import { resolve, dirname } from "node:path";
import { execSync } from "node:child_process";
import { fileURLToPath } from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const root = resolve(__dirname, "..");
const keyPath = resolve(root, ".tauri/signing-key");
try {
process.env.TAURI_SIGNING_PRIVATE_KEY = readFileSync(keyPath, "utf-8").trim();
process.env.TAURI_SIGNING_PRIVATE_KEY_PASSWORD = "";
} catch {
console.error(`错误: 未找到签名密钥 ${keyPath}`);
console.error("请运行: pnpm tauri signer generate -w .tauri/signing-key -p \"\" --ci");
process.exit(1);
}
execSync("pnpm tauri build", { stdio: "inherit", cwd: root });
+103
View File
@@ -0,0 +1,103 @@
/*
* @file /scripts/bump-version.mjs
* @description 统一更新 Tauri 项目版本号
* @author tsl (randy1924@163.com)
* @date 2026-03-23 10:23:42
* @lastModified 2026-03-23 10:25:08
* @lastModifiedBy tsl (randy1924@163.com)
* @example node scripts/bump-version.mjs [patch|minor|major|x.y.z]
* @default patch
*/
import { readFileSync, writeFileSync } from "node:fs";
import { resolve, dirname } from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const root = resolve(__dirname, "..");
// 读取当前版本
function getCurrentVersion() {
const pkg = JSON.parse(readFileSync(resolve(root, "package.json"), "utf-8"));
return pkg.version;
}
// 根据 bump 类型计算新版本
function bumpVersion(current, type) {
const parts = current.replace(/-.*$/, "").split(".").map(Number);
switch (type) {
case "major":
return `${parts[0] + 1}.0.0`;
case "minor":
return `${parts[0]}.${parts[1] + 1}.0`;
case "patch":
return `${parts[0]}.${parts[1]}.${parts[2] + 1}`;
default:
return null;
}
}
const arg = process.argv[2] || "patch";
const BUMP_TYPES = ["patch", "minor", "major"];
const current = getCurrentVersion();
let version;
if (BUMP_TYPES.includes(arg)) {
version = bumpVersion(current, arg);
} else if (/^\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?$/.test(arg)) {
version = arg;
} else {
console.error(`错误: 无效参数 "${arg}",应为 patch / minor / major 或 x.y.z 格式`);
process.exit(1);
}
const files = [
{
path: "package.json",
update(content) {
const json = JSON.parse(content);
const old = json.version;
json.version = version;
return { result: JSON.stringify(json, null, 2) + "\n", old };
},
},
{
path: "src-tauri/tauri.conf.json",
update(content) {
const json = JSON.parse(content);
const old = json.version;
json.version = version;
return { result: JSON.stringify(json, null, 2) + "\n", old };
},
},
{
path: "src-tauri/Cargo.toml",
update(content) {
let old = "";
let replaced = false;
const result = content.replace(
/^version\s*=\s*"([^"]*)"/m,
(match, v) => {
if (replaced) return match;
replaced = true;
old = v;
return `version = "${version}"`;
}
);
return { result, old };
},
},
];
console.log(`\n${current}${version} (${BUMP_TYPES.includes(arg) ? arg : "指定版本"})\n`);
for (const file of files) {
const filePath = resolve(root, file.path);
const content = readFileSync(filePath, "utf-8");
const { result, old } = file.update(content);
writeFileSync(filePath, result, "utf-8");
console.log(`${file.path} ${old}${version}`);
}
console.log("\n全部更新完成!");
console.log("提示: package-lock.json 和 Cargo.lock 会在下次 install/build 时自动同步\n");
+120
View File
@@ -0,0 +1,120 @@
#!/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);
}