wp-blank-scripts 4.0.0-alpha.2 → 4.0.0-alpha.4

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.
@@ -1,13 +1,14 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
- const mysql = require('mysql');
3
+ const ora = require('ora');
4
4
  const Rsync = require('rsync');
5
5
  const { rimraf } = require('rimraf');
6
6
 
7
7
  const exportSql = require('./exportSQL');
8
8
  const cleanShellPath = require('../utils/cleanShellPath');
9
- const tunnel = require('../utils/tunnelSsh');
10
9
  const git = require('../utils/git');
10
+ const _ssh2 = require('ssh2');
11
+ const SSH2Client = _ssh2.Client || _ssh2;
11
12
  const runProjectBuildTask = require('../utils/runProjectBuildTask');
12
13
  const bumpVersion = require('../utils/bumpVersion');
13
14
  const execAsync = require('../utils/execAsync');
@@ -15,7 +16,6 @@ const { DEPLOY_MODES } = require('../constants');
15
16
  const getProjectPath = require('../utils/getProjectPath');
16
17
  const getSettings = require('../utils/projectSettings');
17
18
  const logger = require('../logger');
18
- const replaceSQL = require('../utils/replaceSQL');
19
19
 
20
20
  // Default options
21
21
  const defaultOptions = {
@@ -24,9 +24,6 @@ const defaultOptions = {
24
24
  mySQLPort: 3306,
25
25
  };
26
26
 
27
- let m;
28
- let t;
29
-
30
27
  let options;
31
28
  let settings;
32
29
  let deployModeOptions;
@@ -61,44 +58,86 @@ function setDeployModeOptions(deployBuildDir) {
61
58
  };
62
59
  }
63
60
 
64
- async function createTunnel() {
65
- // Get server access info
61
+ async function deployMySQLviaSSH(file) {
66
62
  const server = settings.server[options.environment];
67
63
  const serverPassword = options.serverPassword;
68
-
69
- const { tunnelHost, tunnelPort, mySQLPort } = options;
64
+ const { user: dbUser, password: dbPassword, database } = settings.mysql[options.environment];
70
65
 
71
66
  let serverPrivateKey;
72
67
  if (options.serverPrivateKey) {
73
68
  serverPrivateKey = fs.readFileSync(cleanShellPath(options.serverPrivateKey));
74
69
  }
75
70
 
76
- // Setup SSL Tunnel for remote MySQL access
77
- const tunnelConfig = {
78
- username: server.user,
79
- host: server.host,
80
- password: serverPassword,
81
- dstHost: server.host,
82
- dstPort: mySQLPort,
83
- localHost: tunnelHost,
84
- localPort: tunnelPort,
85
- privateKey: serverPrivateKey,
86
- };
71
+ const spinner = ora(`Connecting to ${server.host} for MySQL import...`).start();
87
72
 
88
73
  return new Promise((resolve, reject) => {
89
- t = tunnel(tunnelConfig, (error) => {
90
- if (error) {
91
- reject(new Error(`Error connecting: ${error}`));
92
- return;
93
- }
74
+ const conn = new SSH2Client();
75
+
76
+ conn.on('ready', () => {
77
+ spinner.text = `Importing SQL into ${database}...`;
78
+
79
+ // Wrap password in single quotes, escaping any single quotes within it
80
+ const escapedPassword = dbPassword.replace(/'/g, "'\\''");
81
+ const cmd = `mysql -u ${dbUser} -p'${escapedPassword}' ${database}`;
94
82
 
95
- logger.log(`Created tunnel to ${tunnelConfig.host}`);
96
- resolve();
83
+ conn.exec(cmd, (err, stream) => {
84
+ if (err) {
85
+ conn.end();
86
+ spinner.fail('MySQL import failed');
87
+ reject(new Error(`SSH exec error: ${err.message}`));
88
+ return;
89
+ }
90
+
91
+ let stderr = '';
92
+ stream.resume(); // drain stdout so the stream can close
93
+ stream.stderr.on('data', (data) => {
94
+ stderr += data.toString();
95
+ });
96
+
97
+ stream.on('close', (code) => {
98
+ conn.end();
99
+ // Filter the harmless password-on-cli warning from stderr
100
+ const errorOutput = stderr
101
+ .replace(/.*Using a password on the command line.*\n?/g, '')
102
+ .trim();
103
+ if (code !== 0) {
104
+ spinner.fail('MySQL import failed');
105
+ reject(new Error(`MySQL import failed (exit ${code}): ${errorOutput}`));
106
+ } else {
107
+ spinner.succeed('SQL deployment was successful');
108
+ resolve();
109
+ }
110
+ });
111
+
112
+ // Pipe SQL file and explicitly end stdin when done
113
+ const sqlStream = fs.createReadStream(file);
114
+ sqlStream.on('end', () => stream.stdin.end());
115
+ sqlStream.on('error', (err) => {
116
+ spinner.fail('Failed to read SQL file');
117
+ reject(new Error(`SQL file read error: ${err.message}`));
118
+ });
119
+ sqlStream.pipe(stream.stdin, { end: false });
120
+ });
97
121
  });
98
122
 
99
- t.on('error', (error) => {
100
- reject(new Error(`${error}`));
123
+ conn.on('error', (err) => {
124
+ spinner.fail('SSH connection error');
125
+ reject(new Error(`SSH connection error: ${err.message}`));
101
126
  });
127
+
128
+ const connectConfig = {
129
+ host: server.host,
130
+ port: server.sshPort || 22,
131
+ username: server.user,
132
+ };
133
+
134
+ if (serverPrivateKey) {
135
+ connectConfig.privateKey = serverPrivateKey;
136
+ } else if (serverPassword) {
137
+ connectConfig.password = serverPassword;
138
+ }
139
+
140
+ conn.connect(connectConfig);
102
141
  });
103
142
  }
104
143
 
@@ -175,72 +214,6 @@ async function deployToServer() {
175
214
  });
176
215
  }
177
216
 
178
- async function connectMySQL() {
179
- // Environment info
180
- const { host } = settings.server[options.environment];
181
- const { user, password, database } = settings.mysql[options.environment];
182
-
183
- // Tunnel info
184
- const { tunnelHost, tunnelPort } = options;
185
-
186
- return new Promise((resolve, reject) => {
187
- m = mysql.createConnection({
188
- host: tunnelHost,
189
- port: tunnelPort,
190
- user,
191
- password,
192
- database,
193
- multipleStatements: true,
194
- });
195
-
196
- m.connect((err) => {
197
- if (err) {
198
- reject(err);
199
- return;
200
- }
201
-
202
- logger.log(`Connected to ${host} as id ${m.threadId}`);
203
- resolve();
204
- });
205
- });
206
- }
207
-
208
- async function deployMySQL(file) {
209
- return new Promise((resolve, reject) => {
210
- if (!file || !fs.existsSync(file)) {
211
- reject(new Error('SQL file missing'));
212
- return;
213
- }
214
-
215
- logger.log('Starting SQL deployment');
216
-
217
- const sql = fs.readFileSync(file).toString();
218
- m.query(sql, (error) => {
219
- if (error) {
220
- reject(new Error(`failed: ${error}`));
221
- return;
222
- }
223
-
224
- logger.log('SQL deployment was successful');
225
- resolve();
226
- });
227
- });
228
- }
229
-
230
- async function disconnectMySQL() {
231
- return new Promise((resolve, reject) => {
232
- m.end((err) => {
233
- if (err) {
234
- reject(new Error(`Error disconnecting: ${err.stack}`));
235
- return;
236
- }
237
-
238
- logger.log('Disconnected from MySQL server');
239
- resolve();
240
- });
241
- });
242
- }
243
-
244
217
  module.exports = async (selectOptions, callbacks) => {
245
218
  options = {
246
219
  ...defaultOptions,
@@ -274,20 +247,10 @@ module.exports = async (selectOptions, callbacks) => {
274
247
 
275
248
  if (options.sql) {
276
249
  const file = await exportSql({ environment: options.environment });
277
- await createTunnel();
278
- await connectMySQL();
279
250
 
280
251
  if (file) {
281
- await replaceSQL({
282
- environmentIn: 'local',
283
- environmentOut: options.environment,
284
- file,
285
- });
286
-
287
- await deployMySQL(file);
252
+ await deployMySQLviaSSH(file);
288
253
  }
289
-
290
- await disconnectMySQL();
291
254
  }
292
255
 
293
256
  await bumpVersion(options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wp-blank-scripts",
3
- "version": "4.0.0-alpha.2",
3
+ "version": "4.0.0-alpha.4",
4
4
  "description": "Personal Wordpress Scripts",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -55,7 +55,6 @@
55
55
  "inquirer": "3.0.4",
56
56
  "lint-staged": "^13.3.0",
57
57
  "mini-css-extract-plugin": "^2.10.1",
58
- "mysql": "^2.18.1",
59
58
  "node-fetch": "^2.7.0",
60
59
  "ora": "^5.4.1",
61
60
  "postcss": "^8.5.8",
@@ -303,7 +303,8 @@ function makeBaseConfig(options) {
303
303
  sourceMap: !isProd,
304
304
  additionalData: (content, loaderContext) =>
305
305
  loaderContext.resourcePath.endsWith('.css') ? content : sassVariables + content,
306
- sassOptions: {
306
+ sassOptions: (loaderContext) => ({
307
+ syntax: loaderContext.resourcePath.endsWith('.css') ? 'scss' : undefined,
307
308
  loadPaths: [process.cwd()],
308
309
  // Handle @import 'node_modules/foo/bar' resolving to a .css file.
309
310
  // Dart Sass won't find .css files when the extension is omitted, so
@@ -331,7 +332,7 @@ function makeBaseConfig(options) {
331
332
  // project-by-project via: wp-scripts migrate-sass
332
333
  // New projects using @use/@forward won't trigger these.
333
334
  silenceDeprecations: ['import', 'color-functions', 'slash-div', 'global-builtin'],
334
- },
335
+ }),
335
336
  },
336
337
  },
337
338
  ],
@@ -1,134 +0,0 @@
1
- const net = require('net');
2
- const { Client: Connection } = require('ssh2');
3
- const events = require('events');
4
-
5
- const noop = () => {};
6
-
7
- function createConfig(config) {
8
- const env = process.env;
9
-
10
- config = {
11
- username: env.TUNNELSSH_USER || env.USER || env.USERNAME || 'root',
12
- port: 22,
13
- host: null,
14
- srcPort: 0,
15
- srcHost: '127.0.0.1',
16
- dstPort: null,
17
- dstHost: '127.0.0.1',
18
- localHost: '127.0.0.1',
19
- localPort: config.dstPort,
20
- agent: process.env.SSH_AUTH_SOCK,
21
- ...config,
22
- };
23
-
24
- if (!config.host) {
25
- throw new Error('host not set');
26
- }
27
-
28
- if (!config.dstPort) {
29
- throw new Error('dstPort not set');
30
- }
31
-
32
- return config;
33
- }
34
-
35
- function bindSSHConnection(config, netConnection) {
36
- const sshConnection = new Connection();
37
- netConnection.on('close', sshConnection.end.bind(sshConnection));
38
-
39
- sshConnection.on('ready', function () {
40
- netConnection.emit('sshConnection', sshConnection, netConnection);
41
- sshConnection.forwardOut(
42
- config.srcHost,
43
- config.srcPort,
44
- config.dstHost,
45
- config.dstPort,
46
- function (err, sshStream) {
47
- if (err) {
48
- // Bubble up the error => netConnection => server
49
- netConnection.emit('error', err);
50
- return;
51
- }
52
-
53
- netConnection.emit('sshStream', sshStream);
54
- netConnection.pipe(sshStream).pipe(netConnection);
55
- }
56
- );
57
- });
58
- return sshConnection;
59
- }
60
-
61
- function createServer(config) {
62
- let server;
63
- const connections = [];
64
- let connectionCount = 0;
65
-
66
- server = net.createServer(function (netConnection) {
67
- let sshConnection;
68
- connectionCount++;
69
- netConnection.on('error', server.emit.bind(server, 'error'));
70
- netConnection.on('close', function () {
71
- connectionCount--;
72
- if (connectionCount === 0) {
73
- if (!config.keepAlive) {
74
- setTimeout(function () {
75
- if (connectionCount === 0) {
76
- server.close();
77
- }
78
- }, 2);
79
- }
80
- }
81
- });
82
-
83
- server.emit('netConnection', netConnection, server);
84
- sshConnection = bindSSHConnection(config, netConnection);
85
- sshConnection.on('error', server.emit.bind(server, 'error'));
86
-
87
- netConnection.on('sshStream', function (sshStream) {
88
- sshStream.on('error', function () {
89
- server.close();
90
- });
91
- });
92
-
93
- connections.push(sshConnection, netConnection);
94
- try {
95
- sshConnection.connect(config);
96
- } catch (error) {
97
- server.emit('error', error);
98
- }
99
- });
100
-
101
- server.on('close', function () {
102
- connections.forEach(function (connection) {
103
- connection.end();
104
- });
105
- });
106
-
107
- return server;
108
- }
109
-
110
- function tunnel(configArgs, callback) {
111
- let server;
112
- let config;
113
-
114
- if (!callback) {
115
- callback = noop;
116
- }
117
- try {
118
- config = createConfig(configArgs);
119
- server = createServer(config);
120
-
121
- server.listen(config.localPort, config.localHost, function (error) {
122
- callback(error, server);
123
- });
124
- } catch (e) {
125
- server = new events.EventEmitter();
126
- setImmediate(function () {
127
- callback(e);
128
- server.emit('error', e);
129
- });
130
- }
131
- return server;
132
- }
133
-
134
- module.exports = tunnel;