@mindbase/deploy 1.0.0 → 1.0.1
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/LICENSE +201 -0
- package/bin/index.ts +3 -0
- package/bin/shared.ts +66 -0
- package/package.json +13 -13
- package/scripts/ensure-tsx.cjs +18 -0
- package/src/app.ts +156 -0
- package/src/config/manager.ts +56 -0
- package/src/config/schema.ts +102 -0
- package/src/index.ts +2 -0
- package/src/init/app.ts +415 -0
- package/src/script/parser.ts +28 -0
- package/src/script/runner.ts +88 -0
- package/src/server/app.ts +266 -0
- package/src/ssh/client.ts +62 -0
- package/src/ssh/executor.ts +43 -0
- package/dist/bin/index.d.ts +0 -1
- package/dist/bin/index.js +0 -245
- package/dist/bin/index.js.map +0 -1
- package/dist/chunk-YB2FK4HH.js +0 -626
- package/dist/chunk-YB2FK4HH.js.map +0 -1
- package/dist/executor-OQZFWKVP.js +0 -38
- package/dist/executor-OQZFWKVP.js.map +0 -1
- package/dist/index.d.ts +0 -19
- package/dist/index.js +0 -3
- package/dist/index.js.map +0 -1
package/dist/chunk-YB2FK4HH.js
DELETED
|
@@ -1,626 +0,0 @@
|
|
|
1
|
-
import * as clack2 from '@clack/prompts';
|
|
2
|
-
import pc from 'picocolors';
|
|
3
|
-
import { noteBox } from '@mindbase/cli-ui';
|
|
4
|
-
import { existsSync, writeFileSync, readFileSync, mkdirSync } from 'fs';
|
|
5
|
-
import { join, resolve } from 'path';
|
|
6
|
-
import { homedir } from 'os';
|
|
7
|
-
import SftpClient from 'ssh2-sftp-client';
|
|
8
|
-
import spawn from 'cross-spawn';
|
|
9
|
-
|
|
10
|
-
// src/app.ts
|
|
11
|
-
var defaultConfig = {
|
|
12
|
-
servers: {},
|
|
13
|
-
projects: {}
|
|
14
|
-
};
|
|
15
|
-
var CONFIG_DIR = join(homedir(), ".mindbase");
|
|
16
|
-
var CONFIG_PATH = join(CONFIG_DIR, "deploy.json");
|
|
17
|
-
function ensureConfigDir() {
|
|
18
|
-
if (!existsSync(CONFIG_DIR)) {
|
|
19
|
-
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
function getConfig() {
|
|
23
|
-
if (!existsSync(CONFIG_PATH)) {
|
|
24
|
-
ensureConfigDir();
|
|
25
|
-
writeFileSync(CONFIG_PATH, JSON.stringify(defaultConfig, null, 2), "utf-8");
|
|
26
|
-
return structuredClone(defaultConfig);
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
const content = readFileSync(CONFIG_PATH, "utf-8");
|
|
30
|
-
return JSON.parse(content);
|
|
31
|
-
} catch {
|
|
32
|
-
return structuredClone(defaultConfig);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
function setConfig(config) {
|
|
36
|
-
ensureConfigDir();
|
|
37
|
-
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
|
|
38
|
-
}
|
|
39
|
-
function getConfigPath() {
|
|
40
|
-
return CONFIG_PATH;
|
|
41
|
-
}
|
|
42
|
-
function resolvePath(path) {
|
|
43
|
-
if (path.startsWith("~/")) {
|
|
44
|
-
return `${homedir()}${path.slice(1)}`;
|
|
45
|
-
}
|
|
46
|
-
return path;
|
|
47
|
-
}
|
|
48
|
-
function buildConnectConfig(config) {
|
|
49
|
-
const base = {
|
|
50
|
-
host: config.host,
|
|
51
|
-
port: config.port,
|
|
52
|
-
username: config.username
|
|
53
|
-
};
|
|
54
|
-
if (config.privateKeyPath) {
|
|
55
|
-
return {
|
|
56
|
-
...base,
|
|
57
|
-
privateKey: readFileSync(resolvePath(config.privateKeyPath)),
|
|
58
|
-
passphrase: config.passphrase || void 0
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
return {
|
|
62
|
-
...base,
|
|
63
|
-
password: config.password
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
async function connectSftp(name, config) {
|
|
67
|
-
const sftp = new SftpClient(name);
|
|
68
|
-
await sftp.connect(buildConnectConfig(config));
|
|
69
|
-
return sftp;
|
|
70
|
-
}
|
|
71
|
-
async function testConnection(config) {
|
|
72
|
-
const sftp = new SftpClient("test");
|
|
73
|
-
try {
|
|
74
|
-
await sftp.connect(buildConnectConfig(config));
|
|
75
|
-
return true;
|
|
76
|
-
} catch {
|
|
77
|
-
return false;
|
|
78
|
-
} finally {
|
|
79
|
-
await sftp.end();
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// src/script/parser.ts
|
|
84
|
-
function resolveVariables(template, project) {
|
|
85
|
-
const vars = {
|
|
86
|
-
localDir: project.localDir,
|
|
87
|
-
remoteDir: project.remoteDir,
|
|
88
|
-
projectName: project.name
|
|
89
|
-
};
|
|
90
|
-
return template.replace(/\$\{(\w+)\}/g, (match, key) => {
|
|
91
|
-
return vars[key] !== void 0 ? vars[key] : match;
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// src/script/runner.ts
|
|
96
|
-
function runLocal(cmd, cwd) {
|
|
97
|
-
return new Promise((resolve2, reject) => {
|
|
98
|
-
const cp = spawn(cmd, [], {
|
|
99
|
-
cwd,
|
|
100
|
-
detached: false,
|
|
101
|
-
shell: true
|
|
102
|
-
});
|
|
103
|
-
if (cp.stdout) cp.stdout.pipe(process.stdout);
|
|
104
|
-
if (cp.stderr) cp.stderr.pipe(process.stderr);
|
|
105
|
-
cp.on("close", (code) => {
|
|
106
|
-
if (code === 0) {
|
|
107
|
-
resolve2();
|
|
108
|
-
} else {
|
|
109
|
-
reject(new Error(`\u672C\u5730\u547D\u4EE4\u6267\u884C\u5931\u8D25 (code=${code}): ${cmd}`));
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
cp.on("error", (err) => {
|
|
113
|
-
reject(err);
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
async function runStep(step, project, sftp) {
|
|
118
|
-
switch (step.type) {
|
|
119
|
-
case "log": {
|
|
120
|
-
const msg = resolveVariables(step.message, project);
|
|
121
|
-
console.log(msg);
|
|
122
|
-
break;
|
|
123
|
-
}
|
|
124
|
-
case "local": {
|
|
125
|
-
const cmd = resolveVariables(step.cmd, project);
|
|
126
|
-
const cwd = step.cwd ? resolveVariables(step.cwd, project) : void 0;
|
|
127
|
-
await runLocal(cmd, cwd);
|
|
128
|
-
break;
|
|
129
|
-
}
|
|
130
|
-
case "remote": {
|
|
131
|
-
const { execRemote } = await import('./executor-OQZFWKVP.js');
|
|
132
|
-
const cmd = resolveVariables(step.cmd, project);
|
|
133
|
-
await execRemote(sftp, cmd);
|
|
134
|
-
break;
|
|
135
|
-
}
|
|
136
|
-
case "uploadDir": {
|
|
137
|
-
const local = resolveVariables(step.local, project);
|
|
138
|
-
const remote = resolveVariables(step.remote, project);
|
|
139
|
-
await sftp.mkdir(remote, true);
|
|
140
|
-
await sftp.uploadDir(local, remote, { useFastput: true });
|
|
141
|
-
break;
|
|
142
|
-
}
|
|
143
|
-
case "uploadFile": {
|
|
144
|
-
const local = resolveVariables(step.local, project);
|
|
145
|
-
const remote = resolveVariables(step.remote, project);
|
|
146
|
-
await sftp.fastPut(local, remote);
|
|
147
|
-
break;
|
|
148
|
-
}
|
|
149
|
-
case "downloadDir": {
|
|
150
|
-
const remote = resolveVariables(step.remote, project);
|
|
151
|
-
const local = resolveVariables(step.local, project);
|
|
152
|
-
await sftp.downloadDir(remote, local);
|
|
153
|
-
break;
|
|
154
|
-
}
|
|
155
|
-
case "downloadFile": {
|
|
156
|
-
const remote = resolveVariables(step.remote, project);
|
|
157
|
-
const local = resolveVariables(step.local, project);
|
|
158
|
-
await sftp.fastGet(remote, local);
|
|
159
|
-
break;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
async function runSteps(steps, project, sftp) {
|
|
164
|
-
for (const step of steps) {
|
|
165
|
-
await runStep(step, project, sftp);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// src/app.ts
|
|
170
|
-
function handleCancel(result) {
|
|
171
|
-
if (typeof result === "symbol" && clack2.isCancel(result)) {
|
|
172
|
-
clack2.cancel("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
|
|
173
|
-
process.exit(0);
|
|
174
|
-
}
|
|
175
|
-
return result;
|
|
176
|
-
}
|
|
177
|
-
function showConfig() {
|
|
178
|
-
clack2.intro("\u914D\u7F6E\u4FE1\u606F");
|
|
179
|
-
const config = getConfig();
|
|
180
|
-
const path = getConfigPath();
|
|
181
|
-
noteBox(`\u914D\u7F6E\u6587\u4EF6: ${path}
|
|
182
|
-
|
|
183
|
-
${JSON.stringify(config, null, 2)}`, "\u5F53\u524D\u914D\u7F6E");
|
|
184
|
-
clack2.outro("\u5B8C\u6210");
|
|
185
|
-
}
|
|
186
|
-
async function runProject(projectId, serverOverride) {
|
|
187
|
-
const config = getConfig();
|
|
188
|
-
const project = config.projects[projectId];
|
|
189
|
-
if (!project) {
|
|
190
|
-
clack2.log.error(`\u9879\u76EE "${projectId}" \u4E0D\u5B58\u5728`);
|
|
191
|
-
const available = Object.keys(config.projects);
|
|
192
|
-
if (available.length > 0) {
|
|
193
|
-
clack2.log.info(`\u53EF\u7528\u9879\u76EE: ${available.join(", ")}`);
|
|
194
|
-
}
|
|
195
|
-
process.exit(1);
|
|
196
|
-
}
|
|
197
|
-
const serverId = serverOverride || project.server;
|
|
198
|
-
const serverConfig = config.servers[serverId];
|
|
199
|
-
if (!serverConfig) {
|
|
200
|
-
clack2.log.error(`\u670D\u52A1\u5668 "${serverId}" \u4E0D\u5B58\u5728`);
|
|
201
|
-
process.exit(1);
|
|
202
|
-
}
|
|
203
|
-
clack2.intro(`\u90E8\u7F72 ${pc.cyan(project.name)} \u2192 ${pc.cyan(serverId)}`);
|
|
204
|
-
const spinner3 = clack2.spinner();
|
|
205
|
-
spinner3.start("\u8FDE\u63A5\u670D\u52A1\u5668...");
|
|
206
|
-
const sftp = await connectSftp(projectId, serverConfig);
|
|
207
|
-
spinner3.stop("\u5DF2\u8FDE\u63A5");
|
|
208
|
-
try {
|
|
209
|
-
await runSteps(project.steps, project, sftp);
|
|
210
|
-
clack2.log.success(`${project.name} \u90E8\u7F72\u5B8C\u6210`);
|
|
211
|
-
} catch (err) {
|
|
212
|
-
clack2.log.error(`\u90E8\u7F72\u5931\u8D25: ${err}`);
|
|
213
|
-
} finally {
|
|
214
|
-
await sftp.end();
|
|
215
|
-
}
|
|
216
|
-
clack2.outro("\u5B8C\u6210");
|
|
217
|
-
}
|
|
218
|
-
async function runApp() {
|
|
219
|
-
const config = getConfig();
|
|
220
|
-
const serverIds = Object.keys(config.servers);
|
|
221
|
-
const projectIds = Object.keys(config.projects);
|
|
222
|
-
if (serverIds.length === 0) {
|
|
223
|
-
clack2.log.error("\u6CA1\u6709\u5DF2\u914D\u7F6E\u7684\u670D\u52A1\u5668\uFF0C\u8BF7\u5148\u8FD0\u884C deploy server add");
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
if (projectIds.length === 0) {
|
|
227
|
-
clack2.log.error("\u6CA1\u6709\u5DF2\u914D\u7F6E\u7684\u9879\u76EE\uFF0C\u8BF7\u5148\u8FD0\u884C deploy init");
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
clack2.intro("deploy");
|
|
231
|
-
const serverId = handleCancel(
|
|
232
|
-
await clack2.select({
|
|
233
|
-
message: "\u9009\u62E9\u76EE\u6807\u670D\u52A1\u5668",
|
|
234
|
-
options: serverIds.map((id) => ({
|
|
235
|
-
value: id,
|
|
236
|
-
label: `${id} (${config.servers[id].host}:${config.servers[id].port})`
|
|
237
|
-
}))
|
|
238
|
-
})
|
|
239
|
-
);
|
|
240
|
-
const filteredProjects = projectIds.filter(
|
|
241
|
-
(id) => config.projects[id].server === serverId
|
|
242
|
-
);
|
|
243
|
-
const selectableProjects = filteredProjects.length > 0 ? filteredProjects : projectIds;
|
|
244
|
-
const selectedProjects = handleCancel(
|
|
245
|
-
await clack2.multiselect({
|
|
246
|
-
message: "\u9009\u62E9\u8981\u90E8\u7F72\u7684\u9879\u76EE\uFF08\u7A7A\u683C\u5207\u6362\uFF0Ca \u5168\u9009\uFF09",
|
|
247
|
-
options: selectableProjects.map((id) => ({
|
|
248
|
-
value: id,
|
|
249
|
-
label: `${config.projects[id].name} (${id})`
|
|
250
|
-
})),
|
|
251
|
-
required: true
|
|
252
|
-
})
|
|
253
|
-
);
|
|
254
|
-
const spinner3 = clack2.spinner();
|
|
255
|
-
spinner3.start(`\u8FDE\u63A5 ${serverId}...`);
|
|
256
|
-
const serverConfig = config.servers[serverId];
|
|
257
|
-
const sftp = await connectSftp("deploy", serverConfig);
|
|
258
|
-
spinner3.stop("\u5DF2\u8FDE\u63A5");
|
|
259
|
-
try {
|
|
260
|
-
for (const projectId of selectedProjects) {
|
|
261
|
-
const project = config.projects[projectId];
|
|
262
|
-
const effectiveProject = {
|
|
263
|
-
...project,
|
|
264
|
-
server: serverId
|
|
265
|
-
};
|
|
266
|
-
clack2.log.step(`\u5F00\u59CB\u90E8\u7F72 ${pc.cyan(project.name)}`);
|
|
267
|
-
try {
|
|
268
|
-
await runSteps(project.steps, effectiveProject, sftp);
|
|
269
|
-
clack2.log.success(`${project.name} \u90E8\u7F72\u5B8C\u6210`);
|
|
270
|
-
} catch (err) {
|
|
271
|
-
clack2.log.error(`${project.name} \u90E8\u7F72\u5931\u8D25: ${err}`);
|
|
272
|
-
const continueDeploy = handleCancel(
|
|
273
|
-
await clack2.confirm({ message: "\u662F\u5426\u7EE7\u7EED\u90E8\u7F72\u4E0B\u4E00\u4E2A\u9879\u76EE\uFF1F" })
|
|
274
|
-
);
|
|
275
|
-
if (!continueDeploy) break;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
} finally {
|
|
279
|
-
await sftp.end();
|
|
280
|
-
}
|
|
281
|
-
clack2.outro("\u5168\u90E8\u5B8C\u6210");
|
|
282
|
-
}
|
|
283
|
-
function handleCancel2(result) {
|
|
284
|
-
if (typeof result === "symbol" && clack2.isCancel(result)) {
|
|
285
|
-
clack2.cancel("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
|
|
286
|
-
process.exit(0);
|
|
287
|
-
}
|
|
288
|
-
return result;
|
|
289
|
-
}
|
|
290
|
-
function formatStepSummary(step) {
|
|
291
|
-
switch (step.type) {
|
|
292
|
-
case "log":
|
|
293
|
-
return `log: ${step.message}`;
|
|
294
|
-
case "local":
|
|
295
|
-
return step.cwd ? `local: ${step.cmd} (cwd: ${step.cwd})` : `local: ${step.cmd}`;
|
|
296
|
-
case "remote":
|
|
297
|
-
return `remote: ${step.cmd}`;
|
|
298
|
-
case "uploadDir":
|
|
299
|
-
return `uploadDir: ${step.local} \u2192 ${step.remote}`;
|
|
300
|
-
case "uploadFile":
|
|
301
|
-
return `uploadFile: ${step.local} \u2192 ${step.remote}`;
|
|
302
|
-
case "downloadDir":
|
|
303
|
-
return `downloadDir: ${step.remote} \u2192 ${step.local}`;
|
|
304
|
-
case "downloadFile":
|
|
305
|
-
return `downloadFile: ${step.remote} \u2192 ${step.local}`;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
function showStepsSummary(steps) {
|
|
309
|
-
const lines = steps.map((s, i) => `${i + 1}. ${formatStepSummary(s)}`).join("\n");
|
|
310
|
-
noteBox(lines, `\u5DF2\u914D\u7F6E\u6B65\u9AA4 (${steps.length})`);
|
|
311
|
-
}
|
|
312
|
-
var VARS_REFERENCE = [
|
|
313
|
-
"\u53EF\u7528\u53D8\u91CF:",
|
|
314
|
-
" ${localDir} \u9879\u76EE\u672C\u5730\u76EE\u5F55",
|
|
315
|
-
" ${remoteDir} \u9879\u76EE\u8FDC\u7A0B\u76EE\u5F55",
|
|
316
|
-
" ${projectName} \u9879\u76EE\u540D\u79F0"
|
|
317
|
-
].join("\n");
|
|
318
|
-
var STEP_EXAMPLES = {
|
|
319
|
-
log: [
|
|
320
|
-
"\u793A\u4F8B:",
|
|
321
|
-
" \u5F00\u59CB\u53D1\u5E03...",
|
|
322
|
-
" \u7F16\u8BD1\u5B8C\u6210"
|
|
323
|
-
].join("\n"),
|
|
324
|
-
local: [
|
|
325
|
-
VARS_REFERENCE,
|
|
326
|
-
"",
|
|
327
|
-
"\u793A\u4F8B:",
|
|
328
|
-
" npm run build",
|
|
329
|
-
" pnpm install",
|
|
330
|
-
"",
|
|
331
|
-
"cwd: \u5DE5\u4F5C\u76EE\u5F55\uFF0C\u7559\u7A7A\u4F7F\u7528\u9ED8\u8BA4\uFF0C\u53EF\u7528 ${localDir}"
|
|
332
|
-
].join("\n"),
|
|
333
|
-
remote: [
|
|
334
|
-
VARS_REFERENCE,
|
|
335
|
-
"",
|
|
336
|
-
"\u793A\u4F8B:",
|
|
337
|
-
" cd ${remoteDir} && rm -rf ./*",
|
|
338
|
-
" mkdir -p ${remoteDir}src",
|
|
339
|
-
" pm2 restart myapp"
|
|
340
|
-
].join("\n"),
|
|
341
|
-
uploadDir: [
|
|
342
|
-
VARS_REFERENCE,
|
|
343
|
-
"",
|
|
344
|
-
"\u793A\u4F8B:",
|
|
345
|
-
" \u672C\u5730: ${localDir}/dist",
|
|
346
|
-
" \u8FDC\u7AEF: ${remoteDir}"
|
|
347
|
-
].join("\n"),
|
|
348
|
-
uploadFile: [
|
|
349
|
-
VARS_REFERENCE,
|
|
350
|
-
"",
|
|
351
|
-
"\u793A\u4F8B:",
|
|
352
|
-
" \u672C\u5730: ${localDir}/package.json",
|
|
353
|
-
" \u8FDC\u7AEF: ${remoteDir}package.json"
|
|
354
|
-
].join("\n"),
|
|
355
|
-
downloadDir: [
|
|
356
|
-
VARS_REFERENCE,
|
|
357
|
-
"",
|
|
358
|
-
"\u793A\u4F8B:",
|
|
359
|
-
" \u8FDC\u7AEF: ${remoteDir}backup/",
|
|
360
|
-
" \u672C\u5730: ${localDir}/backup"
|
|
361
|
-
].join("\n"),
|
|
362
|
-
downloadFile: [
|
|
363
|
-
VARS_REFERENCE,
|
|
364
|
-
"",
|
|
365
|
-
"\u793A\u4F8B:",
|
|
366
|
-
" \u8FDC\u7AEF: ${remoteDir}config.json",
|
|
367
|
-
" \u672C\u5730: ${localDir}/config.json.bak"
|
|
368
|
-
].join("\n")
|
|
369
|
-
};
|
|
370
|
-
var STEP_TYPE_OPTIONS = [
|
|
371
|
-
{ value: "log", label: "\u65E5\u5FD7\u8F93\u51FA", hint: "\u8F93\u51FA\u4FE1\u606F" },
|
|
372
|
-
{ value: "local", label: "\u672C\u5730\u547D\u4EE4", hint: "\u5728\u672C\u5730\u6267\u884C shell \u547D\u4EE4" },
|
|
373
|
-
{ value: "remote", label: "\u8FDC\u7A0B\u547D\u4EE4", hint: "\u5728\u670D\u52A1\u5668\u6267\u884C shell \u547D\u4EE4" },
|
|
374
|
-
{ value: "uploadDir", label: "\u4E0A\u4F20\u76EE\u5F55", hint: "\u4E0A\u4F20\u6574\u4E2A\u76EE\u5F55\u5230\u670D\u52A1\u5668" },
|
|
375
|
-
{ value: "uploadFile", label: "\u4E0A\u4F20\u6587\u4EF6", hint: "\u4E0A\u4F20\u5355\u4E2A\u6587\u4EF6\u5230\u670D\u52A1\u5668" },
|
|
376
|
-
{ value: "downloadDir", label: "\u4E0B\u8F7D\u76EE\u5F55\uFF08\u5907\u4EFD\uFF09", hint: "\u4ECE\u670D\u52A1\u5668\u4E0B\u8F7D\u6574\u4E2A\u76EE\u5F55" },
|
|
377
|
-
{ value: "downloadFile", label: "\u4E0B\u8F7D\u6587\u4EF6\uFF08\u5907\u4EFD\uFF09", hint: "\u4ECE\u670D\u52A1\u5668\u4E0B\u8F7D\u5355\u4E2A\u6587\u4EF6" }
|
|
378
|
-
];
|
|
379
|
-
function getDefaultProjectName(cwd) {
|
|
380
|
-
const pkgPath = resolve(cwd, "package.json");
|
|
381
|
-
if (existsSync(pkgPath)) {
|
|
382
|
-
try {
|
|
383
|
-
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
384
|
-
if (pkg.name) return pkg.name;
|
|
385
|
-
} catch {
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
return "";
|
|
389
|
-
}
|
|
390
|
-
async function browseRemoteDir(sftp, currentPath) {
|
|
391
|
-
while (true) {
|
|
392
|
-
let entries;
|
|
393
|
-
try {
|
|
394
|
-
entries = await sftp.list(currentPath);
|
|
395
|
-
} catch {
|
|
396
|
-
return currentPath;
|
|
397
|
-
}
|
|
398
|
-
const dirOptions = entries.filter((e) => e.type === "d").map((e) => ({ value: e.name, label: `\u{1F4C1} ${e.name}` }));
|
|
399
|
-
const choices = [
|
|
400
|
-
{ value: "__confirm__", label: pc.green(`\u2713 \u4F7F\u7528\u5F53\u524D\u76EE\u5F55: ${currentPath}`) },
|
|
401
|
-
{ value: "__manual__", label: pc.yellow("\u270E \u624B\u52A8\u8F93\u5165\u8DEF\u5F84") },
|
|
402
|
-
...dirOptions
|
|
403
|
-
];
|
|
404
|
-
const selected = handleCancel2(
|
|
405
|
-
await clack2.select({
|
|
406
|
-
message: `\u6D4F\u89C8\u8FDC\u7AEF\u76EE\u5F55: ${currentPath}`,
|
|
407
|
-
options: choices
|
|
408
|
-
})
|
|
409
|
-
);
|
|
410
|
-
if (selected === "__confirm__") {
|
|
411
|
-
return currentPath;
|
|
412
|
-
}
|
|
413
|
-
if (selected === "__manual__") {
|
|
414
|
-
const input = handleCancel2(
|
|
415
|
-
await clack2.text({
|
|
416
|
-
message: "\u8F93\u5165\u8FDC\u7AEF\u76EE\u5F55\u8DEF\u5F84",
|
|
417
|
-
initialValue: currentPath
|
|
418
|
-
})
|
|
419
|
-
);
|
|
420
|
-
currentPath = input;
|
|
421
|
-
continue;
|
|
422
|
-
}
|
|
423
|
-
currentPath = currentPath.endsWith("/") ? `${currentPath}${selected}` : `${currentPath}/${selected}`;
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
async function collectStep() {
|
|
427
|
-
const stepType = handleCancel2(
|
|
428
|
-
await clack2.select({
|
|
429
|
-
message: "\u9009\u62E9\u6B65\u9AA4\u7C7B\u578B",
|
|
430
|
-
options: STEP_TYPE_OPTIONS
|
|
431
|
-
})
|
|
432
|
-
);
|
|
433
|
-
noteBox(STEP_EXAMPLES[stepType], "\u53C2\u8003\uFF08\u53EF\u76F4\u63A5\u590D\u5236\u53D8\u91CF\uFF09");
|
|
434
|
-
switch (stepType) {
|
|
435
|
-
case "log": {
|
|
436
|
-
const message = handleCancel2(
|
|
437
|
-
await clack2.text({ message: "\u65E5\u5FD7\u4FE1\u606F" })
|
|
438
|
-
);
|
|
439
|
-
return { type: "log", message };
|
|
440
|
-
}
|
|
441
|
-
case "local": {
|
|
442
|
-
const cmd = handleCancel2(
|
|
443
|
-
await clack2.text({ message: "\u547D\u4EE4" })
|
|
444
|
-
);
|
|
445
|
-
const cwd = handleCancel2(
|
|
446
|
-
await clack2.text({
|
|
447
|
-
message: "\u5DE5\u4F5C\u76EE\u5F55\uFF08\u53EF\u9009\uFF0C\u7559\u7A7A\u4F7F\u7528\u9ED8\u8BA4\uFF09",
|
|
448
|
-
placeholder: "${localDir}"
|
|
449
|
-
})
|
|
450
|
-
);
|
|
451
|
-
const step = { type: "local", cmd };
|
|
452
|
-
if (cwd) step.cwd = cwd;
|
|
453
|
-
return step;
|
|
454
|
-
}
|
|
455
|
-
case "remote": {
|
|
456
|
-
const cmd = handleCancel2(
|
|
457
|
-
await clack2.text({ message: "\u8FDC\u7A0B\u547D\u4EE4" })
|
|
458
|
-
);
|
|
459
|
-
return { type: "remote", cmd };
|
|
460
|
-
}
|
|
461
|
-
case "uploadDir": {
|
|
462
|
-
const local = handleCancel2(
|
|
463
|
-
await clack2.text({ message: "\u672C\u5730\u76EE\u5F55", placeholder: "${localDir}/dist" })
|
|
464
|
-
);
|
|
465
|
-
const remote = handleCancel2(
|
|
466
|
-
await clack2.text({ message: "\u8FDC\u7AEF\u76EE\u5F55", placeholder: "${remoteDir}" })
|
|
467
|
-
);
|
|
468
|
-
return { type: "uploadDir", local, remote };
|
|
469
|
-
}
|
|
470
|
-
case "uploadFile": {
|
|
471
|
-
const local = handleCancel2(
|
|
472
|
-
await clack2.text({ message: "\u672C\u5730\u6587\u4EF6\u8DEF\u5F84" })
|
|
473
|
-
);
|
|
474
|
-
const remote = handleCancel2(
|
|
475
|
-
await clack2.text({ message: "\u8FDC\u7AEF\u6587\u4EF6\u8DEF\u5F84" })
|
|
476
|
-
);
|
|
477
|
-
return { type: "uploadFile", local, remote };
|
|
478
|
-
}
|
|
479
|
-
case "downloadDir": {
|
|
480
|
-
const remote = handleCancel2(
|
|
481
|
-
await clack2.text({ message: "\u8FDC\u7AEF\u76EE\u5F55" })
|
|
482
|
-
);
|
|
483
|
-
const local = handleCancel2(
|
|
484
|
-
await clack2.text({ message: "\u672C\u5730\u4FDD\u5B58\u76EE\u5F55" })
|
|
485
|
-
);
|
|
486
|
-
return { type: "downloadDir", remote, local };
|
|
487
|
-
}
|
|
488
|
-
case "downloadFile": {
|
|
489
|
-
const remote = handleCancel2(
|
|
490
|
-
await clack2.text({ message: "\u8FDC\u7AEF\u6587\u4EF6\u8DEF\u5F84" })
|
|
491
|
-
);
|
|
492
|
-
const local = handleCancel2(
|
|
493
|
-
await clack2.text({ message: "\u672C\u5730\u4FDD\u5B58\u8DEF\u5F84" })
|
|
494
|
-
);
|
|
495
|
-
return { type: "downloadFile", remote, local };
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
async function runInit(cwd) {
|
|
500
|
-
clack2.intro("deploy init");
|
|
501
|
-
const deployConfig = getConfig();
|
|
502
|
-
const defaultName = getDefaultProjectName(cwd);
|
|
503
|
-
const projectId = handleCancel2(
|
|
504
|
-
await clack2.text({
|
|
505
|
-
message: "\u9879\u76EE ID\uFF08\u7528\u4E8E\u6807\u8BC6\uFF09",
|
|
506
|
-
initialValue: defaultName
|
|
507
|
-
})
|
|
508
|
-
);
|
|
509
|
-
if (deployConfig.projects[projectId]) {
|
|
510
|
-
clack2.log.warn(`\u9879\u76EE "${projectId}" \u5DF2\u5B58\u5728\uFF0C\u5C06\u8986\u76D6\u914D\u7F6E`);
|
|
511
|
-
}
|
|
512
|
-
const name = handleCancel2(
|
|
513
|
-
await clack2.text({
|
|
514
|
-
message: "\u9879\u76EE\u663E\u793A\u540D\u79F0",
|
|
515
|
-
initialValue: projectId
|
|
516
|
-
})
|
|
517
|
-
);
|
|
518
|
-
const serverIds = Object.keys(deployConfig.servers);
|
|
519
|
-
if (serverIds.length === 0) {
|
|
520
|
-
clack2.log.error("\u6CA1\u6709\u5DF2\u914D\u7F6E\u7684\u670D\u52A1\u5668\uFF0C\u8BF7\u5148\u8FD0\u884C deploy server add \u6DFB\u52A0\u670D\u52A1\u5668");
|
|
521
|
-
clack2.outro("\u8BF7\u5148\u914D\u7F6E\u670D\u52A1\u5668");
|
|
522
|
-
return;
|
|
523
|
-
}
|
|
524
|
-
const serverId = handleCancel2(
|
|
525
|
-
await clack2.select({
|
|
526
|
-
message: "\u9009\u62E9\u76EE\u6807\u670D\u52A1\u5668",
|
|
527
|
-
options: serverIds.map((id) => ({
|
|
528
|
-
value: id,
|
|
529
|
-
label: `${id} (${deployConfig.servers[id].host})`
|
|
530
|
-
}))
|
|
531
|
-
})
|
|
532
|
-
);
|
|
533
|
-
const localDir = handleCancel2(
|
|
534
|
-
await clack2.text({
|
|
535
|
-
message: "\u672C\u5730\u76EE\u5F55\uFF08\u7EDD\u5BF9\u8DEF\u5F84\uFF09",
|
|
536
|
-
initialValue: cwd
|
|
537
|
-
})
|
|
538
|
-
);
|
|
539
|
-
const spinner3 = clack2.spinner();
|
|
540
|
-
spinner3.start("\u8FDE\u63A5\u670D\u52A1\u5668...");
|
|
541
|
-
let sftp;
|
|
542
|
-
try {
|
|
543
|
-
sftp = await connectSftp("init", deployConfig.servers[serverId]);
|
|
544
|
-
spinner3.stop("\u5DF2\u8FDE\u63A5");
|
|
545
|
-
} catch (err) {
|
|
546
|
-
spinner3.stop("\u8FDE\u63A5\u5931\u8D25");
|
|
547
|
-
clack2.log.error(`\u65E0\u6CD5\u8FDE\u63A5\u670D\u52A1\u5668: ${err}`);
|
|
548
|
-
clack2.outro("\u8FDE\u63A5\u5931\u8D25");
|
|
549
|
-
return;
|
|
550
|
-
}
|
|
551
|
-
let remoteDir;
|
|
552
|
-
try {
|
|
553
|
-
const browseChoice = handleCancel2(
|
|
554
|
-
await clack2.select({
|
|
555
|
-
message: "\u8FDC\u7AEF\u76EE\u5F55\u8BBE\u7F6E\u65B9\u5F0F",
|
|
556
|
-
options: [
|
|
557
|
-
{ value: "browse", label: "\u6D4F\u89C8\u670D\u52A1\u5668\u76EE\u5F55" },
|
|
558
|
-
{ value: "manual", label: "\u624B\u52A8\u8F93\u5165\u8DEF\u5F84" }
|
|
559
|
-
]
|
|
560
|
-
})
|
|
561
|
-
);
|
|
562
|
-
if (browseChoice === "browse") {
|
|
563
|
-
remoteDir = await browseRemoteDir(sftp, "/");
|
|
564
|
-
} else {
|
|
565
|
-
remoteDir = handleCancel2(
|
|
566
|
-
await clack2.text({
|
|
567
|
-
message: "\u8FDC\u7AEF\u76EE\u5F55\u8DEF\u5F84",
|
|
568
|
-
placeholder: "/appliction/my-app/"
|
|
569
|
-
})
|
|
570
|
-
);
|
|
571
|
-
const confirmMkdir = handleCancel2(
|
|
572
|
-
await clack2.confirm({ message: `\u662F\u5426\u81EA\u52A8\u521B\u5EFA\u76EE\u5F55 ${remoteDir}\uFF08\u5982\u679C\u4E0D\u5B58\u5728\uFF09\uFF1F` })
|
|
573
|
-
);
|
|
574
|
-
if (confirmMkdir) {
|
|
575
|
-
await sftp.mkdir(remoteDir, true);
|
|
576
|
-
clack2.log.success(`\u76EE\u5F55\u5DF2\u521B\u5EFA: ${remoteDir}`);
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
} finally {
|
|
580
|
-
await sftp.end();
|
|
581
|
-
}
|
|
582
|
-
const steps = [];
|
|
583
|
-
clack2.log.info("\u5F00\u59CB\u914D\u7F6E\u90E8\u7F72\u6B65\u9AA4\uFF08\u6BCF\u4E2A\u6B65\u9AA4\u4F1A\u5C55\u793A\u53C2\u8003\u548C\u53EF\u7528\u53D8\u91CF\uFF09");
|
|
584
|
-
while (true) {
|
|
585
|
-
if (steps.length > 0) {
|
|
586
|
-
const action = handleCancel2(
|
|
587
|
-
await clack2.select({
|
|
588
|
-
message: `\u5DF2\u914D\u7F6E ${steps.length} \u4E2A\u6B65\u9AA4`,
|
|
589
|
-
options: [
|
|
590
|
-
{ value: "add", label: "\u6DFB\u52A0\u6B65\u9AA4" },
|
|
591
|
-
{ value: "done", label: "\u5B8C\u6210\u914D\u7F6E" }
|
|
592
|
-
]
|
|
593
|
-
})
|
|
594
|
-
);
|
|
595
|
-
if (action === "done") break;
|
|
596
|
-
}
|
|
597
|
-
const step = await collectStep();
|
|
598
|
-
if (step) {
|
|
599
|
-
steps.push(step);
|
|
600
|
-
showStepsSummary(steps);
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
const projectConfig = {
|
|
604
|
-
name,
|
|
605
|
-
localDir: resolve(localDir),
|
|
606
|
-
server: serverId,
|
|
607
|
-
remoteDir,
|
|
608
|
-
steps
|
|
609
|
-
};
|
|
610
|
-
noteBox(JSON.stringify(projectConfig, null, 2), "\u9879\u76EE\u914D\u7F6E\u9884\u89C8");
|
|
611
|
-
const confirmSave = handleCancel2(
|
|
612
|
-
await clack2.confirm({ message: "\u786E\u8BA4\u4FDD\u5B58\u6B64\u914D\u7F6E\uFF1F" })
|
|
613
|
-
);
|
|
614
|
-
if (confirmSave) {
|
|
615
|
-
deployConfig.projects[projectId] = projectConfig;
|
|
616
|
-
setConfig(deployConfig);
|
|
617
|
-
clack2.log.success(`\u9879\u76EE "${projectId}" \u914D\u7F6E\u5DF2\u4FDD\u5B58`);
|
|
618
|
-
} else {
|
|
619
|
-
clack2.log.info("\u5DF2\u53D6\u6D88\u4FDD\u5B58");
|
|
620
|
-
}
|
|
621
|
-
clack2.outro("\u5B8C\u6210");
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
export { getConfig, runApp, runInit, runProject, setConfig, showConfig, testConnection };
|
|
625
|
-
//# sourceMappingURL=chunk-YB2FK4HH.js.map
|
|
626
|
-
//# sourceMappingURL=chunk-YB2FK4HH.js.map
|