@zhengyizhao/deploy-helper 0.1.0 → 0.2.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/src/utils/ssh.js CHANGED
@@ -24,7 +24,7 @@ export async function connectSSH(config) {
24
24
  // 在服务器上执行命令,并实时打印输出
25
25
  export async function runRemote(ssh, command, label) {
26
26
  if (label) console.log(chalk.gray(` → ${label}`));
27
-
27
+
28
28
  const result = await ssh.execCommand(command, {
29
29
  onStdout: (chunk) => process.stdout.write(chalk.gray(' ' + chunk.toString())),
30
30
  onStderr: (chunk) => process.stdout.write(chalk.yellow(' ' + chunk.toString())),
@@ -36,22 +36,47 @@ export async function runRemote(ssh, command, label) {
36
36
  return result.stdout.trim();
37
37
  }
38
38
 
39
- // 静默执行(不打印输出)
39
+ // 静默执行(不打印输出);默认不抛错,返回 { stdout, stderr, code }。
40
+ // 调用方需要根据 code 判断是否成功。
40
41
  export async function runRemoteSilent(ssh, command) {
41
42
  const result = await ssh.execCommand(command);
42
- return { stdout: result.stdout.trim(), code: result.code };
43
+ return {
44
+ stdout: result.stdout.trim(),
45
+ stderr: result.stderr.trim(),
46
+ code: result.code,
47
+ };
48
+ }
49
+
50
+ // 静默执行 + 失败抛错:用于"必须成功"的步骤(如安装、启动)。
51
+ export async function runRemoteStrict(ssh, command) {
52
+ const result = await runRemoteSilent(ssh, command);
53
+ if (result.code !== 0 && result.code !== null) {
54
+ const tail = (result.stderr || result.stdout || '').split('\n').slice(-6).join('\n');
55
+ throw new Error(`命令失败 (exit ${result.code})\n${tail}`);
56
+ }
57
+ return result;
43
58
  }
44
59
 
45
60
  // 上传本地目录到服务器
46
- export async function uploadDirectory(ssh, localPath, remotePath, ora) {
61
+ // skipPatterns: 覆盖默认跳过列表(不传则用默认)
62
+ // uploadEnv: true 时允许上传 .env
63
+ export async function uploadDirectory(ssh, localPath, remotePath, options = {}) {
64
+ const {
65
+ uploadEnv = false,
66
+ skipPatterns = ['node_modules', '.git', 'dist', '__pycache__', '.DS_Store', '.venv', 'venv'],
67
+ } = options;
68
+
69
+ const alwaysSkip = new Set(skipPatterns);
47
70
  const failed = [];
71
+
48
72
  await ssh.putDirectory(localPath, remotePath, {
49
73
  recursive: true,
50
74
  concurrency: 5,
51
75
  validate: (itemPath) => {
52
- const base = itemPath.split('/').pop();
53
- // 跳过不必要的目录
54
- return !['node_modules', '.git', '.env', 'dist', '__pycache__', '.DS_Store'].includes(base);
76
+ const base = itemPath.split(/[\\/]/).pop();
77
+ if (alwaysSkip.has(base)) return false;
78
+ if (base === '.env' && !uploadEnv) return false;
79
+ return true;
55
80
  },
56
81
  tick: (localFile, remoteFile, error) => {
57
82
  if (error) failed.push(localFile);