@taole/deploy-helper 1.0.4 → 1.0.5-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.mjs +11 -4
- package/lib/git.mjs +102 -0
- package/lib/lightDeploy.mjs +103 -0
- package/lib/project.mjs +1 -1
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -10,6 +10,8 @@ import path from 'path';
|
|
|
10
10
|
import { fileURLToPath } from 'url';
|
|
11
11
|
import { cmdWhoami, cmdLogout, cmdLogin } from './lib/login.mjs';
|
|
12
12
|
import { cmdProjectCreate, cmdProjectPublish, cmdProjectPull } from './lib/project.mjs';
|
|
13
|
+
import { cmdCommit } from './lib/git.mjs';
|
|
14
|
+
import { lightDeploy } from './lib/lightDeploy.mjs';
|
|
13
15
|
|
|
14
16
|
const __filename = fileURLToPath(import.meta.url);
|
|
15
17
|
const __dirname = path.dirname(__filename);
|
|
@@ -106,10 +108,10 @@ async function getScpClient() {
|
|
|
106
108
|
return scpClient;
|
|
107
109
|
}
|
|
108
110
|
|
|
109
|
-
|
|
111
|
+
function getPackageJson() {
|
|
110
112
|
const packageJsonPath = join(__dirname, "package.json");
|
|
111
113
|
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
112
|
-
return packageJson
|
|
114
|
+
return packageJson;
|
|
113
115
|
}
|
|
114
116
|
|
|
115
117
|
const commandMap = {};
|
|
@@ -128,6 +130,7 @@ function doRegisterCommands() {
|
|
|
128
130
|
registerCommand("create", cmdProjectCreate, "创建项目");
|
|
129
131
|
registerCommand("publish", cmdProjectPublish, "更新项目到H5平台");
|
|
130
132
|
registerCommand("pull", cmdProjectPull, "拉取已有项目到本地");
|
|
133
|
+
registerCommand("commit", cmdCommit, "按任务号提交(参数为说明,如 feat: xxx)");
|
|
131
134
|
registerCommand("whoami", cmdWhoami, "查看当前登录用户信息");
|
|
132
135
|
registerCommand("logout", cmdLogout, "退出登录");
|
|
133
136
|
registerCommand("login", cmdLogin, "登录");
|
|
@@ -136,7 +139,8 @@ function doRegisterCommands() {
|
|
|
136
139
|
doRegisterCommands();
|
|
137
140
|
|
|
138
141
|
async function main() {
|
|
139
|
-
const
|
|
142
|
+
const packageJson = getPackageJson();
|
|
143
|
+
const version = packageJson.version;
|
|
140
144
|
|
|
141
145
|
// process.argv.includes("--debug") ||
|
|
142
146
|
// 默认开启debug debug目前只是打印日志的时候额外打印时间
|
|
@@ -283,7 +287,10 @@ async function main() {
|
|
|
283
287
|
process.exit(1);
|
|
284
288
|
}
|
|
285
289
|
|
|
286
|
-
|
|
290
|
+
const needHandleLight = config.type === "ddfe:cdn";
|
|
291
|
+
if(needHandleLight){
|
|
292
|
+
await lightDeploy(config, mode);
|
|
293
|
+
}
|
|
287
294
|
const needHandleAssets = config.assets && config.assets.dest;
|
|
288
295
|
|
|
289
296
|
// 需要处理entry
|
package/lib/git.mjs
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// Git 辅助操作(基于 simple-git)
|
|
2
|
+
import { simpleGit } from "simple-git";
|
|
3
|
+
import { log } from "./util.mjs";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {string} branch
|
|
7
|
+
* @param {string} latestCommitMsg
|
|
8
|
+
*/
|
|
9
|
+
function extractTaskId(branch, latestCommitMsg) {
|
|
10
|
+
const fromBranch = branch.match(/#([A-Z]+-\d+)$/);
|
|
11
|
+
if (fromBranch) return fromBranch[1];
|
|
12
|
+
const fromCommit = latestCommitMsg.match(/-#([A-Z]+-\d+)/);
|
|
13
|
+
if (fromCommit) return fromCommit[1];
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function getUserMessage() {
|
|
18
|
+
const argvMsg = process.argv.slice(3).join(" ").trim();
|
|
19
|
+
if (argvMsg) return argvMsg;
|
|
20
|
+
const envMsg = (
|
|
21
|
+
process.env.npm_config_message ||
|
|
22
|
+
process.env.npm_config_msg ||
|
|
23
|
+
""
|
|
24
|
+
).trim();
|
|
25
|
+
return envMsg;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {string} input
|
|
30
|
+
* @returns {{ full: string, typePart: null } | { full: null, typePart: string } | null}
|
|
31
|
+
*/
|
|
32
|
+
/** 参数是否已自带 `-#PROJ-123` 形式任务前缀(无需再从分支/历史解析) */
|
|
33
|
+
function hasExplicitTaskPrefix(msg) {
|
|
34
|
+
return /^-#[A-Z]+-\d+/.test(msg.trim());
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function normalizeMessage(input) {
|
|
38
|
+
const msg = input.trim();
|
|
39
|
+
if (!msg) return null;
|
|
40
|
+
if (msg.startsWith("-#")) {
|
|
41
|
+
return { full: msg, typePart: null };
|
|
42
|
+
}
|
|
43
|
+
const match = msg.match(/^([a-z]+):\s*(.+)$/i);
|
|
44
|
+
if (!match) return null;
|
|
45
|
+
return { full: null, typePart: `${match[1]}: ${match[2]}` };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function getLatestSubject(git) {
|
|
49
|
+
try {
|
|
50
|
+
const logResult = await git.log({ maxCount: 1 });
|
|
51
|
+
if (!logResult.latest) return "";
|
|
52
|
+
return logResult.latest.message.split("\n")[0].trim();
|
|
53
|
+
} catch {
|
|
54
|
+
return "";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 按任务号规范提交:默认从分支名(末尾 #任务号)或最新提交中提取任务号;若参数已含 `-#DDKH-4169` 形式前缀则直接使用该说明提交。
|
|
60
|
+
* 用法: dh commit "feat: 说明" 或 dh commit "-#DDKH-4169 feat: 完整信息"
|
|
61
|
+
*/
|
|
62
|
+
export async function cmdCommit() {
|
|
63
|
+
const git = simpleGit(process.cwd());
|
|
64
|
+
const rawMsg = getUserMessage();
|
|
65
|
+
|
|
66
|
+
let commitMsg;
|
|
67
|
+
|
|
68
|
+
if (rawMsg.trim() && hasExplicitTaskPrefix(rawMsg)) {
|
|
69
|
+
const parsed = normalizeMessage(rawMsg);
|
|
70
|
+
if (!parsed) {
|
|
71
|
+
log('请传入提交说明,例如: dh commit "feat:我的提交信息"');
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
commitMsg = parsed.full;
|
|
75
|
+
} else {
|
|
76
|
+
const branch = (await git.status()).current;
|
|
77
|
+
const latestCommitMsg = await getLatestSubject(git);
|
|
78
|
+
const taskId = extractTaskId(branch, latestCommitMsg);
|
|
79
|
+
if (!taskId) {
|
|
80
|
+
log("未能从分支名或最新提交中提取任务号(如 DDKH-4169)");
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const parsed = normalizeMessage(rawMsg);
|
|
85
|
+
if (!parsed) {
|
|
86
|
+
log('请传入提交说明,例如: dh commit "feat:我的提交信息"');
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
commitMsg = parsed.full || `-#${taskId} ${parsed.typePart}`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const st = await git.status();
|
|
94
|
+
if (st.isClean()) {
|
|
95
|
+
log("没有可提交的改动");
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
await git.add(".");
|
|
99
|
+
await git.commit(commitMsg);
|
|
100
|
+
log(`commit 完成: ${commitMsg}`);
|
|
101
|
+
process.exit(0);
|
|
102
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { log } from "./util.mjs";
|
|
4
|
+
import { getCache as getLoginCache } from "./login.mjs";
|
|
5
|
+
import { genArchive } from "./project.mjs";
|
|
6
|
+
|
|
7
|
+
const isDev = false;
|
|
8
|
+
const apiHost = isDev ? "http://localhost:9000" : "https://fapi.tuwan.com";
|
|
9
|
+
|
|
10
|
+
function getErrorMessage(resJson, fallback) {
|
|
11
|
+
const message = resJson?.message;
|
|
12
|
+
if (Array.isArray(message)) {
|
|
13
|
+
return message.join(", ");
|
|
14
|
+
}
|
|
15
|
+
if (message) {
|
|
16
|
+
return String(message);
|
|
17
|
+
}
|
|
18
|
+
return fallback;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function apiCdnUpload({ distZipPath, prefix, mode, includeHtml, entryHtmlMap }, userCache) {
|
|
22
|
+
const formData = new FormData();
|
|
23
|
+
formData.append("prefix", prefix);
|
|
24
|
+
formData.append("mode", mode);
|
|
25
|
+
formData.append("includeHtml", includeHtml ? "true" : "false");
|
|
26
|
+
if (entryHtmlMap) {
|
|
27
|
+
const entryHtmlMapStr =
|
|
28
|
+
typeof entryHtmlMap === "string" ? entryHtmlMap : JSON.stringify(entryHtmlMap);
|
|
29
|
+
formData.append("entryHtmlMap", entryHtmlMapStr);
|
|
30
|
+
}
|
|
31
|
+
formData.append(
|
|
32
|
+
"file",
|
|
33
|
+
new Blob([fs.readFileSync(distZipPath)], { type: "application/zip" }),
|
|
34
|
+
"dist.zip"
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
const res = await fetch(`${apiHost}/cdn/upload`, {
|
|
38
|
+
method: "POST",
|
|
39
|
+
body: formData,
|
|
40
|
+
headers: {
|
|
41
|
+
Cookie: `Tuwan_Passport=${userCache.Tuwan_Passport}`,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
const resJson = await res.json();
|
|
45
|
+
if (!res.ok) {
|
|
46
|
+
throw new Error(getErrorMessage(resJson, "CDN 上传失败"));
|
|
47
|
+
}
|
|
48
|
+
return resJson;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function lightDeploy(config, mode) {
|
|
52
|
+
log(`light模式, 开始部署`, { mode, prefix: config.prefix, includeHtml: config.includeHtml });
|
|
53
|
+
|
|
54
|
+
if (!mode || (mode !== "test" && mode !== "prod")) {
|
|
55
|
+
throw new Error("部署环境无效,仅支持 test 或 prod");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const prefix = config.prefix;
|
|
59
|
+
if (!prefix) {
|
|
60
|
+
throw new Error("配置缺少 prefix");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const userCache = await getLoginCache();
|
|
64
|
+
if (!userCache?.userInfo?.uid) {
|
|
65
|
+
throw new Error("请先登录");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const workDir = process.cwd();
|
|
69
|
+
const distDir = config.distDir || "dist";
|
|
70
|
+
const distPath = path.join(workDir, distDir);
|
|
71
|
+
if (!fs.existsSync(distPath)) {
|
|
72
|
+
throw new Error(`${distPath} 不存在,请先执行构建`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const distZipPath = path.join(workDir, "dist.zip");
|
|
76
|
+
if (fs.existsSync(distZipPath)) {
|
|
77
|
+
fs.unlinkSync(distZipPath);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
log(`开始打包 ${distPath}`);
|
|
81
|
+
await genArchive(distZipPath, distPath);
|
|
82
|
+
log(`打包完成: ${distZipPath}`);
|
|
83
|
+
|
|
84
|
+
const includeHtml = config.includeHtml === true;
|
|
85
|
+
log(`开始上传至 CDN,mode=${mode}, prefix=${prefix}, includeHtml=${includeHtml}`);
|
|
86
|
+
const result = await apiCdnUpload(
|
|
87
|
+
{
|
|
88
|
+
distZipPath,
|
|
89
|
+
prefix,
|
|
90
|
+
mode,
|
|
91
|
+
includeHtml,
|
|
92
|
+
entryHtmlMap: config.entryHtmlMap,
|
|
93
|
+
type: config.cdnType,
|
|
94
|
+
},
|
|
95
|
+
userCache
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
if (fs.existsSync(distZipPath)) {
|
|
99
|
+
fs.unlinkSync(distZipPath);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
log(`CDN 上传成功`, result);
|
|
103
|
+
}
|
package/lib/project.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import { getCache as getLoginCache } from "./login.mjs";
|
|
|
9
9
|
const isDev = false;
|
|
10
10
|
const apiHost = isDev ? "http://localhost:9000" : "https://fapi.tuwan.com";
|
|
11
11
|
|
|
12
|
-
function genArchive(outputPath, dir) {
|
|
12
|
+
export function genArchive(outputPath, dir) {
|
|
13
13
|
return new Promise((resolve, reject) => {
|
|
14
14
|
const output = fs.createWriteStream(outputPath);
|
|
15
15
|
const archive = archiver("zip", {
|