@taole/deploy-helper 1.1.4 → 1.1.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/lib/archive.mjs +61 -0
- package/lib/lightDeploy.mjs +29 -31
- package/lib/project.mjs +25 -29
- package/package.json +1 -1
package/lib/archive.mjs
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { PassThrough } from "stream";
|
|
4
|
+
import archiver from "archiver";
|
|
5
|
+
|
|
6
|
+
export function archiveToBuffer(setupArchive) {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
const chunks = [];
|
|
9
|
+
const output = new PassThrough();
|
|
10
|
+
output.on("data", (chunk) => chunks.push(chunk));
|
|
11
|
+
output.on("end", () => resolve(Buffer.concat(chunks)));
|
|
12
|
+
output.on("error", reject);
|
|
13
|
+
|
|
14
|
+
const archive = archiver("zip", { zlib: { level: 1 } });
|
|
15
|
+
archive.on("error", reject);
|
|
16
|
+
archive.pipe(output);
|
|
17
|
+
|
|
18
|
+
setupArchive(archive);
|
|
19
|
+
archive.finalize();
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function appendDirToArchive(archive, dir, zipPrefix) {
|
|
24
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
25
|
+
const fullPath = path.join(dir, entry.name);
|
|
26
|
+
const entryZipPath = zipPrefix
|
|
27
|
+
? path.posix.join(zipPrefix, entry.name)
|
|
28
|
+
: entry.name;
|
|
29
|
+
if (entry.isDirectory()) {
|
|
30
|
+
appendDirToArchive(archive, fullPath, entryZipPath);
|
|
31
|
+
} else {
|
|
32
|
+
archive.file(fullPath, { name: entryZipPath });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function genProjectArchiveBuffer(distPath) {
|
|
38
|
+
return archiveToBuffer((archive) => {
|
|
39
|
+
archive.directory(distPath, false);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* lib 类型 CDN 打包:若 dist 内仅有名为 version 的子目录则原样打包;
|
|
45
|
+
* 若无子目录则为 zip 内所有文件加上 version 前缀。
|
|
46
|
+
*/
|
|
47
|
+
export function genLibArchiveBuffer(distPath, version) {
|
|
48
|
+
const subdirs = fs
|
|
49
|
+
.readdirSync(distPath, { withFileTypes: true })
|
|
50
|
+
.filter((entry) => entry.isDirectory());
|
|
51
|
+
|
|
52
|
+
return archiveToBuffer((archive) => {
|
|
53
|
+
if (subdirs.length === 1 && subdirs[0].name === version) {
|
|
54
|
+
archive.directory(distPath, false);
|
|
55
|
+
} else if (subdirs.length === 0) {
|
|
56
|
+
appendDirToArchive(archive, distPath, version);
|
|
57
|
+
} else {
|
|
58
|
+
archive.directory(distPath, false);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
package/lib/lightDeploy.mjs
CHANGED
|
@@ -2,7 +2,10 @@ import fs from "fs";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { log } from "./util.mjs";
|
|
4
4
|
import { getCache as getLoginCache } from "./login.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
genLibArchiveBuffer,
|
|
7
|
+
genProjectArchiveBuffer,
|
|
8
|
+
} from "./archive.mjs";
|
|
6
9
|
|
|
7
10
|
const isDev = false;
|
|
8
11
|
const apiHost = isDev ? "http://localhost:9000" : "https://fapi.tuwan.com";
|
|
@@ -19,7 +22,7 @@ function getErrorMessage(resJson, fallback) {
|
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
async function apiCdnUpload(
|
|
22
|
-
{
|
|
25
|
+
{ distZipBuffer, prefix, mode, includeHtml, entryHtmlMap, type, version },
|
|
23
26
|
userCache
|
|
24
27
|
) {
|
|
25
28
|
const formData = new FormData();
|
|
@@ -41,7 +44,7 @@ async function apiCdnUpload(
|
|
|
41
44
|
}
|
|
42
45
|
formData.append(
|
|
43
46
|
"file",
|
|
44
|
-
new Blob([
|
|
47
|
+
new Blob([distZipBuffer], { type: "application/zip" }),
|
|
45
48
|
"dist.zip"
|
|
46
49
|
);
|
|
47
50
|
|
|
@@ -69,6 +72,11 @@ export async function lightDeploy(config, mode) {
|
|
|
69
72
|
fs.readFileSync(path.join(process.cwd(), "package.json"), "utf-8")
|
|
70
73
|
);
|
|
71
74
|
const version = projectJson.version;
|
|
75
|
+
// 校验cdnType只能是lib或者project
|
|
76
|
+
const cdnType = config.cdnType;
|
|
77
|
+
if (cdnType !== "lib" && cdnType !== "project") {
|
|
78
|
+
throw new Error("配置项 cdnType 仅支持 'lib' 或 'project'");
|
|
79
|
+
}
|
|
72
80
|
log(`light模式, 开始部署`, {
|
|
73
81
|
mode,
|
|
74
82
|
prefix: config.prefix,
|
|
@@ -98,14 +106,12 @@ export async function lightDeploy(config, mode) {
|
|
|
98
106
|
throw new Error(`${distPath} 不存在,请先执行构建`);
|
|
99
107
|
}
|
|
100
108
|
|
|
101
|
-
const distZipPath = path.join(workDir, "cdnDist.zip");
|
|
102
|
-
if (fs.existsSync(distZipPath)) {
|
|
103
|
-
fs.unlinkSync(distZipPath);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
109
|
log(`开始打包 ${distPath}`);
|
|
107
|
-
|
|
108
|
-
|
|
110
|
+
const distZipBuffer =
|
|
111
|
+
cdnType === "lib"
|
|
112
|
+
? await genLibArchiveBuffer(distPath, version)
|
|
113
|
+
: await genProjectArchiveBuffer(distPath);
|
|
114
|
+
log(`打包完成,大小 ${distZipBuffer.length} 字节`);
|
|
109
115
|
|
|
110
116
|
const includeHtml = config.includeHtml === true;
|
|
111
117
|
log(
|
|
@@ -113,25 +119,17 @@ export async function lightDeploy(config, mode) {
|
|
|
113
119
|
config.cdnType || "project"
|
|
114
120
|
}, version=${version}, includeHtml=${includeHtml}`
|
|
115
121
|
);
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
log(`CDN 上传成功`, result);
|
|
130
|
-
} catch (error) {
|
|
131
|
-
throw error;
|
|
132
|
-
} finally {
|
|
133
|
-
if (fs.existsSync(distZipPath)) {
|
|
134
|
-
fs.unlinkSync(distZipPath);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
122
|
+
const result = await apiCdnUpload(
|
|
123
|
+
{
|
|
124
|
+
distZipBuffer,
|
|
125
|
+
prefix,
|
|
126
|
+
mode,
|
|
127
|
+
includeHtml,
|
|
128
|
+
entryHtmlMap: config.entryHtmlMap,
|
|
129
|
+
type: config.cdnType,
|
|
130
|
+
version,
|
|
131
|
+
},
|
|
132
|
+
userCache
|
|
133
|
+
);
|
|
134
|
+
log(`CDN 上传成功`, result);
|
|
137
135
|
}
|
package/lib/project.mjs
CHANGED
|
@@ -2,31 +2,30 @@
|
|
|
2
2
|
import { simpleGit } from "simple-git";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import fs from "fs";
|
|
5
|
-
import archiver from "archiver";
|
|
6
5
|
import { log, getJsonConfig, runCmdAsync } from "./util.mjs";
|
|
7
6
|
import { getCache as getLoginCache } from "./login.mjs";
|
|
7
|
+
import { genProjectArchiveBuffer } from "./archive.mjs";
|
|
8
8
|
|
|
9
9
|
const isDev = false;
|
|
10
10
|
const apiHost = isDev ? "http://localhost:9000" : "https://fapi.tuwan.com";
|
|
11
|
+
const WEB_ACT_REPO_PATH = "69b3821af7b43e00d420cb32/Web-Act";
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
archive.finalize();
|
|
29
|
-
});
|
|
13
|
+
function extractWebActProjectNameFromRemote(remoteUrl) {
|
|
14
|
+
if (!remoteUrl) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
const match = remoteUrl.match(new RegExp(`${WEB_ACT_REPO_PATH}/([^/.]+)(?:\\.git)?/?$`));
|
|
18
|
+
return match ? match[1] : null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function checkPackageNameWithGitRemote(git, packageName) {
|
|
22
|
+
const remotes = await git.getRemotes(true);
|
|
23
|
+
const remoteUrls = remotes.flatMap((remote) => [remote.refs.fetch, remote.refs.push]).filter(Boolean);
|
|
24
|
+
const gitProjectName = remoteUrls.map(extractWebActProjectNameFromRemote).find(Boolean);
|
|
25
|
+
|
|
26
|
+
if (gitProjectName && gitProjectName !== packageName) {
|
|
27
|
+
throw new Error(`项目名称不匹配: git仓库项目名称为${gitProjectName}, package.json name为${packageName}`);
|
|
28
|
+
}
|
|
30
29
|
}
|
|
31
30
|
|
|
32
31
|
async function apiDeployProject(name, version, env, userCache) {
|
|
@@ -84,14 +83,14 @@ async function apiCreateProject(name, userCache) {
|
|
|
84
83
|
}
|
|
85
84
|
}
|
|
86
85
|
|
|
87
|
-
async function apiPublishProject(name, version,
|
|
86
|
+
async function apiPublishProject(name, version, distZipBuffer, userCache) {
|
|
88
87
|
const urlPath = `/h5projects/${name}/publish`;
|
|
89
88
|
const formData = new FormData();
|
|
90
89
|
formData.append("updaterUid", userCache.userInfo.uid);
|
|
91
90
|
formData.append("version", version);
|
|
92
91
|
formData.append(
|
|
93
92
|
"file",
|
|
94
|
-
new Blob([
|
|
93
|
+
new Blob([distZipBuffer], { type: "application/zip" }),
|
|
95
94
|
"dist.zip"
|
|
96
95
|
);
|
|
97
96
|
const res = await fetch(`${apiHost}${urlPath}`, {
|
|
@@ -240,6 +239,7 @@ export const cmdProjectPublish = async () => {
|
|
|
240
239
|
log("package.json或者其version字段或name字段不存在");
|
|
241
240
|
process.exit(1);
|
|
242
241
|
}
|
|
242
|
+
await checkPackageNameWithGitRemote(git, packageJson.name);
|
|
243
243
|
|
|
244
244
|
const newVersion = await apiGetProjectVersion(packageJson.name, userCache);
|
|
245
245
|
packageJson.version = newVersion;
|
|
@@ -257,21 +257,17 @@ export const cmdProjectPublish = async () => {
|
|
|
257
257
|
await runCmdAsync(buildCmd);
|
|
258
258
|
log(`构建项目成功,开始打包构建产物`);
|
|
259
259
|
const distPath = path.join(process.cwd(), "dist");
|
|
260
|
-
const distZipPath = path.join(process.cwd(), "dist.zip");
|
|
261
260
|
if (!fs.existsSync(distPath)) {
|
|
262
261
|
log("dist目录不存在");
|
|
263
262
|
process.exit(1);
|
|
264
263
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
}
|
|
269
|
-
await genArchive(distZipPath, distPath);
|
|
270
|
-
log(`dist目录打包为zip包: ${distZipPath}, 开始推送构建产物`);
|
|
264
|
+
log(`开始打包 ${distPath}`);
|
|
265
|
+
const distZipBuffer = await genProjectArchiveBuffer(distPath);
|
|
266
|
+
log(`打包完成,大小 ${distZipBuffer.length} 字节,开始推送构建产物`);
|
|
271
267
|
const _publishResult = await apiPublishProject(
|
|
272
268
|
packageJson.name,
|
|
273
269
|
packageJson.version,
|
|
274
|
-
|
|
270
|
+
distZipBuffer,
|
|
275
271
|
userCache
|
|
276
272
|
);
|
|
277
273
|
log(`构建产物推送成功, 开始部署项目至${env}环境`);
|