@automattic/vip 2.30.0 → 2.31.0

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.
Files changed (56) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/assets/dev-env.lando.template.yml.ejs +14 -0
  3. package/assets/dev-env.nginx.template.conf.ejs +23 -2
  4. package/dist/bin/vip-dev-env-shell.js +2 -1
  5. package/dist/bin/vip-dev-env-sync-sql.js +15 -19
  6. package/dist/bin/vip-dev-env-sync.js +0 -0
  7. package/dist/bin/vip-dev-env-update.js +1 -0
  8. package/dist/bin/vip-export-sql.js +12 -11
  9. package/dist/bin/vip-import-sql.js +2 -2
  10. package/dist/bin/vip-whoami.js +7 -10
  11. package/dist/commands/dev-env-sync-sql.js +53 -20
  12. package/dist/commands/export-sql.js +13 -4
  13. package/dist/lib/analytics/clients/pendo.js +11 -20
  14. package/dist/lib/analytics/clients/tracks.js +12 -12
  15. package/dist/lib/analytics/index.js +9 -12
  16. package/dist/lib/api/app.js +10 -13
  17. package/dist/lib/api/cache-purge.js +3 -10
  18. package/dist/lib/api/feature-flags.js +4 -2
  19. package/dist/lib/api/http.js +10 -18
  20. package/dist/lib/api/user.js +3 -8
  21. package/dist/lib/api.js +11 -14
  22. package/dist/lib/app-logs/app-logs.js +3 -6
  23. package/dist/lib/cli/apiConfig.js +10 -7
  24. package/dist/lib/cli/config.js +2 -3
  25. package/dist/lib/cli/envAlias.js +11 -9
  26. package/dist/lib/cli/exit.js +4 -7
  27. package/dist/lib/cli/format.js +25 -26
  28. package/dist/lib/cli/progress.js +7 -3
  29. package/dist/lib/cli/prompt.js +3 -2
  30. package/dist/lib/client-file-uploader.js +86 -87
  31. package/dist/lib/config/software.js +18 -12
  32. package/dist/lib/dev-environment/dev-environment-cli.js +6 -4
  33. package/dist/lib/dev-environment/dev-environment-configuration-file.js +4 -2
  34. package/dist/lib/dev-environment/dev-environment-core.js +3 -0
  35. package/dist/lib/env.js +16 -13
  36. package/dist/lib/envvar/api-delete.js +2 -0
  37. package/dist/lib/envvar/api-get-all.js +4 -1
  38. package/dist/lib/envvar/api-get.js +3 -1
  39. package/dist/lib/envvar/api-list.js +8 -3
  40. package/dist/lib/envvar/api-set.js +2 -0
  41. package/dist/lib/envvar/api.js +2 -5
  42. package/dist/lib/envvar/input.js +7 -8
  43. package/dist/lib/envvar/read-file.js +4 -7
  44. package/dist/lib/http/proxy-agent.js +5 -4
  45. package/dist/lib/read-file.js +13 -14
  46. package/dist/lib/search-and-replace.js +17 -26
  47. package/dist/lib/tracker.js +12 -12
  48. package/dist/lib/user-error.js +6 -5
  49. package/dist/lib/utils.js +18 -22
  50. package/dist/lib/vip-import-validate-files.js +23 -22
  51. package/npm-shrinkwrap.json +9 -1043
  52. package/package.json +3 -6
  53. package/tsconfig.json +4 -2
  54. package/dist/lib/analytics/clients/stub.js +0 -16
  55. package/dist/lib/cli/repo.js +0 -61
  56. package/noImplictAnyImportBypass.d.ts +0 -6
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  ## Changelog
2
2
 
3
+ ### 2.31.0
4
+
5
+ - #1397 feature(dev-env): Add ability to sync multisites
6
+ - #1399 chore(dev-deps): Remove stub type definitions
7
+ - #1394 FORNO-1609: Combine all error events into one error event
8
+ - #1345 feat(dev-env): Add Photon
9
+ - #1398 Fix coverage generation
10
+ - #1395 Add types for the other ways of using enquirer
11
+ - #1388 Typescript: refactor `vip-whoami`
12
+ - #1393 refactor: Convert `lib/{app-logs,envvar}` to TypeScript
13
+ - #1392 refactor: Convert `lib/config` to TypeScript
14
+ - #1391 refactor: Convert lib to TypeScript
15
+ - #1390 chore(deps): Update @automattic/vip-search-replace to 1.1.1
16
+ - #1389 Replace 'site' by 'environment' in error msg
17
+ - #1385 refactor: Convert lib/api to TypeScript
18
+ - #1387 chore(deps): Update @automattic/vip-search-replace to 1.1.0
19
+ - #1386 fix: Fix `getAbsolutePath()` and convert `utils.js` to TypeScript
20
+ - #1383 fix(dev-env): Pull uniqueLabel field from backend
21
+ - #1382 test: Reduce noise from tests
22
+ - #1384 fix: Add return type to parseEnvAliasFromArgv()
23
+ - #1381 refactor: Convert lib/cli and dependencies to TypeScript
24
+ - #1377 chore: Configure linting for TS files
25
+ - #1380 chore(dev-deps): Remove jest-environment-jsdom
26
+ - #1378 refactor: Convert analytics and dependencies to TypeScript
27
+
3
28
  ### 2.30.0
4
29
 
5
30
  - #1264 feature(dev-env): Add dev-env-sync-sql command
@@ -222,6 +222,20 @@ services:
222
222
  LANDO_NEEDS_EXEC: 1
223
223
  <% } %>
224
224
 
225
+ <% if ( photon ) { %>
226
+ photon:
227
+ type: compose
228
+ services:
229
+ image: ghcr.io/automattic/vip-container-images/photon:latest
230
+ command: /usr/sbin/php-fpm
231
+ environment:
232
+ LANDO_NO_USER_PERMS: 1
233
+ LANDO_NO_SCRIPTS: 1
234
+ LANDO_NEEDS_EXEC: 1
235
+ volumes:
236
+ - ./uploads:/usr/share/webapps/photon/uploads:ro
237
+ <% } %>
238
+
225
239
  tooling:
226
240
  wp:
227
241
  service: php
@@ -1,6 +1,27 @@
1
+ <% if ( photon ) { %>
2
+
3
+ location ^~ /wp-content/uploads/ {
4
+ expires max;
5
+ log_not_found off;
1
6
  <% if ( mediaRedirectDomain ) { %>
7
+ if (!-f $request_filename) {
8
+ rewrite ^/(.*)$ <%= mediaRedirectDomain %>/$1 redirect;
9
+ }
10
+ <% } %>
11
+
12
+ include fastcgi_params;
13
+ fastcgi_param DOCUMENT_ROOT /usr/share/webapps/photon;
14
+ fastcgi_param SCRIPT_FILENAME /usr/share/webapps/photon/index.php;
15
+ fastcgi_param SCRIPT_NAME /index.php;
16
+
17
+ if ($request_uri ~* \.(gif|jpe?g|png)\?) {
18
+ fastcgi_pass photon:9000;
19
+ }
20
+ }
21
+
22
+ <% } else if ( mediaRedirectDomain ) { %>
2
23
 
3
- location ~* /wp-content/uploads {
24
+ location ^~ /wp-content/uploads {
4
25
  expires max;
5
26
  log_not_found off;
6
27
  try_files $uri @prod_site;
@@ -10,4 +31,4 @@ location @prod_site {
10
31
  rewrite ^/(.*)$ <%= mediaRedirectDomain %>/$1 redirect;
11
32
  }
12
33
 
13
- <% } %>
34
+ <% } %>
@@ -29,7 +29,8 @@ const userMap = {
29
29
  elasticsearch: 'elasticsearch',
30
30
  phpmyadmin: 'www-data',
31
31
  mailhog: 'mailhog',
32
- mailpit: 'root'
32
+ mailpit: 'root',
33
+ photon: 'root'
33
34
  };
34
35
  const examples = [{
35
36
  usage: `${_devEnvironment.DEV_ENVIRONMENT_FULL_COMMAND} shell`,
@@ -8,9 +8,12 @@
8
8
  /**
9
9
  * External dependencies
10
10
  */
11
+
12
+ /**
13
+ * Internal dependencies
14
+ */
11
15
  "use strict";
12
16
 
13
- var _chalk = _interopRequireDefault(require("chalk"));
14
17
  var _command = _interopRequireDefault(require("../lib/cli/command"));
15
18
  var _devEnvironmentCore = require("../lib/dev-environment/dev-environment-core");
16
19
  var _devEnvironmentLando = require("../lib/dev-environment/dev-environment-lando");
@@ -19,9 +22,6 @@ var _devEnvSyncSql = require("../commands/dev-env-sync-sql");
19
22
  var _devEnvironment = require("../lib/constants/dev-environment");
20
23
  var _tracker = require("../lib/tracker");
21
24
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
22
- /**
23
- * Internal dependencies
24
- */
25
25
  const examples = [{
26
26
  usage: `${_devEnvironment.DEV_ENVIRONMENT_FULL_COMMAND} sync sql @my-test.develop --slug=my_site`,
27
27
  description: 'Syncs with the `my-test` site\'s `develop` environment database into `my_site`'
@@ -39,6 +39,13 @@ const appQuery = `
39
39
  primaryDomain { name }
40
40
  uniqueLabel
41
41
  isMultisite
42
+ wpSitesSDS(first:500) {
43
+ nodes {
44
+ id
45
+ blogId
46
+ homeUrl
47
+ }
48
+ }
42
49
  }
43
50
  `;
44
51
  (0, _command.default)({
@@ -55,23 +62,10 @@ const appQuery = `
55
62
  const trackerFn = (0, _tracker.makeCommandTracker)('dev_env_sync_sql', {
56
63
  app: app.id,
57
64
  env: env.uniqueLabel,
58
- slug
65
+ slug,
66
+ multisite: env.isMultisite
59
67
  });
60
68
  await trackerFn('execute');
61
- if (env.isMultisite) {
62
- console.log(_chalk.default.yellow('You seem to be trying to sync a SQL database for a network site.'));
63
- console.log(_chalk.default.yellow('Unfortunately, the current version of our tool does not yet support syncing network sites.\n'));
64
- console.log(_chalk.default.yellow('However, you can manually export the database using the following command:'));
65
- console.log(_chalk.default.yellow(_chalk.default.bold(`vip export sql @${app.id}.${env.uniqueLabel} --output=${app.id}-${env.uniqueLabel}-exported.sql.gz\n`)));
66
- console.log(_chalk.default.yellow('After exporting the database, you\'ll need to perform the necessary search and replace operations on the exported file to update any relevant data or configurations.'));
67
- console.log(_chalk.default.yellow('See: https://docs.wpvip.com/how-tos/dev-env-add-content/#h-3-import-the-sql-file\n'));
68
- console.log(_chalk.default.yellow('Once you\'ve made the required changes, you can import the modified SQL file into your development environment using the following command:'));
69
- console.log(_chalk.default.yellow(_chalk.default.bold(`vip dev-env import sql ${app.id}-${env.uniqueLabel}-exported.sql.gz --slug=${slug}`)));
70
- await trackerFn('aborted', {
71
- error_type: 'multisite_not_supported'
72
- });
73
- process.exit(0);
74
- }
75
69
  const lando = await (0, _devEnvironmentLando.bootstrapLando)();
76
70
  const envPath = (0, _devEnvironmentCore.getEnvironmentPath)(slug);
77
71
  if (!(await (0, _devEnvironmentLando.isEnvUp)(lando, envPath))) {
@@ -81,6 +75,8 @@ const appQuery = `
81
75
  throw new _userError.default('Environment needs to be started first');
82
76
  }
83
77
  const cmd = new _devEnvSyncSql.DevEnvSyncSQLCommand(app, env, slug, trackerFn);
78
+ // TODO: There's a function called handleCLIException for dev-env that handles exceptions but DevEnvSyncSQLCommand has its own implementation.
79
+ // We should probably use handleCLIException instead?
84
80
  await cmd.run();
85
81
  await trackerFn('success');
86
82
  });
File without changes
@@ -64,6 +64,7 @@ cmd.argv(process.argv, async (arg, opt) => {
64
64
  phpmyadmin: currentInstanceData.phpmyadmin,
65
65
  xdebug: currentInstanceData.xdebug,
66
66
  mailpit: (_currentInstanceData$ = currentInstanceData.mailpit) !== null && _currentInstanceData$ !== void 0 ? _currentInstanceData$ : currentInstanceData.mailhog,
67
+ photon: currentInstanceData.photon,
67
68
  mediaRedirectDomain: currentInstanceData.mediaRedirectDomain,
68
69
  multisite: false,
69
70
  title: ''
@@ -26,17 +26,18 @@ const examples = [{
26
26
  description: 'The output file can be specified with the --output flag'
27
27
  }];
28
28
  const appQuery = `
29
- id,
30
- name,
31
- type,
32
- organization { id, name },
33
- environments{
34
- id
35
- appId
36
- type
37
- name
38
- primaryDomain { name }
39
- }
29
+ id,
30
+ name,
31
+ type,
32
+ organization { id, name },
33
+ environments{
34
+ id
35
+ appId
36
+ type
37
+ name
38
+ primaryDomain { name }
39
+ uniqueLabel
40
+ }
40
41
  `;
41
42
  (0, _command.default)({
42
43
  appContext: true,
@@ -317,7 +317,7 @@ const displayPlaybook = ({
317
317
  }
318
318
  }
319
319
  };
320
- (0, _command.default)({
320
+ void (0, _command.default)({
321
321
  appContext: true,
322
322
  appQuery,
323
323
  envContext: true,
@@ -498,7 +498,7 @@ Processing the SQL import for your environment...
498
498
  } catch (uploadError) {
499
499
  await track('import_sql_command_error', {
500
500
  error_type: 'upload_failed',
501
- upload_error: uploadError
501
+ upload_error: uploadError.message
502
502
  });
503
503
  progressTracker.stepFailed('upload');
504
504
  return failWithError(uploadError);
@@ -1,10 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- /**
4
- *
5
- * @format
6
- */
7
-
8
3
  /**
9
4
  * External dependencies
10
5
  */
@@ -26,28 +21,30 @@ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "functio
26
21
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
27
22
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
28
23
  async function whoamiCommand() {
24
+ var _currentUser$displayN, _currentUser$id;
29
25
  const trackingParams = {
30
26
  command: 'vip whoami'
31
27
  };
32
28
  await (0, _tracker.trackEvent)('whoami_command_execute', trackingParams);
33
- let currentUser = {};
29
+ let currentUser;
34
30
  try {
35
31
  currentUser = await (0, _user.getCurrentUserInfo)();
36
32
  } catch (err) {
33
+ const error = err instanceof Error ? err : new Error('Unknown error');
37
34
  await (0, _tracker.trackEvent)('whoami_command_error', {
38
35
  ...trackingParams,
39
- error: err.message
36
+ error: error.message
40
37
  });
41
- exit.withError(`Failed to fetch information about the currently logged-in user error: ${err.message}`);
38
+ exit.withError(`Failed to fetch information about the currently logged-in user error: ${error.message}`);
42
39
  }
43
40
  await (0, _tracker.trackEvent)('whoami_command_success', trackingParams);
44
- const output = [`- Howdy ${currentUser.displayName}!`, `- Your user ID is ${currentUser.id}`];
41
+ const output = [`- Howdy ${(_currentUser$displayN = currentUser.displayName) !== null && _currentUser$displayN !== void 0 ? _currentUser$displayN : 'user'}!`, `- Your user ID is ${(_currentUser$id = currentUser.id) !== null && _currentUser$id !== void 0 ? _currentUser$id : ' not found'}`];
45
42
  if (currentUser.isVIP) {
46
43
  output.push('- Your account has VIP Staff permissions');
47
44
  }
48
45
  console.log(output.join('\n'));
49
46
  }
50
- (0, _command.default)({
47
+ void (0, _command.default)({
51
48
  usage: 'vip whoami'
52
49
  }).examples([{
53
50
  usage: 'vip whoami',
@@ -37,13 +37,10 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
37
37
  * @return {string} Site home url. null if not found
38
38
  */
39
39
  function findSiteHomeUrl(sql) {
40
+ var _sql$match;
40
41
  const regex = "'(siteurl|home)',\\s?'(.*?)'";
41
- const results = sql.match(regex);
42
- if (results) {
43
- const url = results[2];
44
- return _url.default.parse(url).hostname;
45
- }
46
- return null;
42
+ const url = ((_sql$match = sql.match(regex)) === null || _sql$match === void 0 ? void 0 : _sql$match[2]) || '';
43
+ return _url.default.parse(url).hostname || null;
47
44
  }
48
45
 
49
46
  /**
@@ -60,11 +57,12 @@ async function extractSiteUrls(sqlFile) {
60
57
  readInterface.on('line', line => {
61
58
  const domain = findSiteHomeUrl(line);
62
59
  if (domain) {
63
- domains.add('//' + domain);
60
+ domains.add(domain);
64
61
  }
65
62
  });
66
63
  readInterface.on('close', () => {
67
- resolve(Array.from(domains));
64
+ // Soring by length so that longest domains are replaced first
65
+ resolve(Array.from(domains).sort((dom1, dom2) => dom2.length - dom1.length));
68
66
  });
69
67
  readInterface.on('error', reject);
70
68
  });
@@ -86,7 +84,7 @@ class DevEnvSyncSQLCommand {
86
84
  this.tmpDir = (0, _utils.makeTempDir)();
87
85
  }
88
86
  get landoDomain() {
89
- return `//${this.slug}.vipdev.lndo.site`;
87
+ return `${this.slug}.vipdev.lndo.site`;
90
88
  }
91
89
  get sqlFile() {
92
90
  return `${this.tmpDir}/sql-export.sql`;
@@ -114,7 +112,7 @@ class DevEnvSyncSQLCommand {
114
112
  * @throws {Error} If there is an error reading the file
115
113
  */
116
114
  async runSearchReplace() {
117
- const replacements = this.siteUrls.reduce((acc, url) => [...acc, url, this.landoDomain], []);
115
+ const replacements = Object.entries(this.searchReplaceMap).flat();
118
116
  const readStream = _fs.default.createReadStream(this.sqlFile);
119
117
  const replacedStream = await (0, _vipSearchReplace.replace)(readStream, replacements);
120
118
  const outputFile = `${this.tmpDir}/sql-export-sr.sql`;
@@ -127,6 +125,20 @@ class DevEnvSyncSQLCommand {
127
125
  replacedStream.on('error', reject);
128
126
  });
129
127
  }
128
+ generateSearchReplaceMap() {
129
+ this.searchReplaceMap = {};
130
+ for (const url of this.siteUrls) {
131
+ this.searchReplaceMap[url] = this.landoDomain;
132
+ }
133
+ const networkSites = this.env.wpSitesSDS.nodes;
134
+ if (!networkSites) return;
135
+ for (const site of networkSites) {
136
+ if (!site.blogId || site.blogId === 1) continue;
137
+ const url = site.homeUrl.replace(/https?:\/\//, '');
138
+ if (!this.searchReplaceMap[url]) continue;
139
+ this.searchReplaceMap[url] = `${site.blogId}.${this.landoDomain}`;
140
+ }
141
+ }
130
142
 
131
143
  /**
132
144
  * Runs the SQL import command to import the SQL file
@@ -153,6 +165,14 @@ class DevEnvSyncSQLCommand {
153
165
  try {
154
166
  await this.generateExport();
155
167
  } catch (err) {
168
+ // this.generateExport probably catches all exceptions, track the event and runs exit.withError() but if things go really wrong
169
+ // and we have no tracking data, we would at least have it logged here.
170
+ // the following will not get executed if this.generateExport() calls exit.withError() on all exception
171
+ await this.track('error', {
172
+ error_type: 'export_sql_backup',
173
+ error_message: err === null || err === void 0 ? void 0 : err.message,
174
+ stack: err === null || err === void 0 ? void 0 : err.stack
175
+ });
156
176
  exit.withError(`Error exporting SQL backup: ${err === null || err === void 0 ? void 0 : err.message}`);
157
177
  }
158
178
  try {
@@ -160,27 +180,38 @@ class DevEnvSyncSQLCommand {
160
180
  await (0, _clientFileUploader.unzipFile)(this.gzFile, this.sqlFile);
161
181
  console.log(`${_chalk.default.green('✓')} Extracted to ${this.sqlFile}`);
162
182
  } catch (err) {
163
- await this.track('archive_extraction_error', {
164
- errorMessage: err === null || err === void 0 ? void 0 : err.message
183
+ await this.track('error', {
184
+ error_type: 'archive_extraction',
185
+ error_message: err === null || err === void 0 ? void 0 : err.message,
186
+ stack: err === null || err === void 0 ? void 0 : err.stack
165
187
  });
166
- exit.withError(`Error extracting the SQL export: ${err === null || err === void 0 ? void 0 : err.message}`);
188
+ exit.withError(`Error extracting the SQL export: ${err.message}`);
167
189
  }
168
190
  try {
169
191
  console.log('Extracting site urls from the SQL file...');
170
192
  this.siteUrls = await extractSiteUrls(this.sqlFile);
171
193
  } catch (err) {
194
+ await this.track('error', {
195
+ error_type: 'extract_site_urls',
196
+ error_message: err === null || err === void 0 ? void 0 : err.message,
197
+ stack: err === null || err === void 0 ? void 0 : err.stack
198
+ });
172
199
  exit.withError(`Error extracting site URLs: ${err === null || err === void 0 ? void 0 : err.message}`);
173
200
  }
201
+ console.log('Generating search-replace configuration...');
202
+ this.generateSearchReplaceMap();
174
203
  try {
175
204
  console.log('Running the following search-replace operations on the SQL file:');
176
- this.siteUrls.forEach(domain => {
177
- console.log(` ${domain} -> ${this.landoDomain}`);
178
- });
205
+ for (const [domain, landoDomain] of Object.entries(this.searchReplaceMap)) {
206
+ console.log(` ${domain} -> ${landoDomain}`);
207
+ }
179
208
  await this.runSearchReplace();
180
209
  console.log(`${_chalk.default.green('✓')} Search-replace operation is complete`);
181
210
  } catch (err) {
182
- await this.track('search_replace_error', {
183
- errorMessage: err === null || err === void 0 ? void 0 : err.message
211
+ await this.track('error', {
212
+ error_type: 'search_replace',
213
+ error_message: err === null || err === void 0 ? void 0 : err.message,
214
+ stack: err === null || err === void 0 ? void 0 : err.stack
184
215
  });
185
216
  exit.withError(`Error replacing domains: ${err === null || err === void 0 ? void 0 : err.message}`);
186
217
  }
@@ -189,8 +220,10 @@ class DevEnvSyncSQLCommand {
189
220
  await this.runImport();
190
221
  console.log(`${_chalk.default.green('✓')} SQL file imported`);
191
222
  } catch (err) {
192
- await this.track('import_error', {
193
- errorMessage: err === null || err === void 0 ? void 0 : err.message
223
+ await this.track('error', {
224
+ error_type: 'import_sql_file',
225
+ error_message: err === null || err === void 0 ? void 0 : err.message,
226
+ stack: err === null || err === void 0 ? void 0 : err.stack
194
227
  });
195
228
  exit.withError(`Error importing SQL file: ${err === null || err === void 0 ? void 0 : err.message}`);
196
229
  }
@@ -322,7 +322,8 @@ class ExportSQLCommand {
322
322
  } catch (err) {
323
323
  await this.track('error', {
324
324
  error_type: 'cannot_write_to_path',
325
- error_message: `Cannot write to the specified path: ${err === null || err === void 0 ? void 0 : err.message}`
325
+ error_message: `Cannot write to the specified path: ${err === null || err === void 0 ? void 0 : err.message}`,
326
+ stack: err === null || err === void 0 ? void 0 : err.stack
326
327
  });
327
328
  exit.withError(`Cannot write to the specified path: ${err === null || err === void 0 ? void 0 : err.message}`);
328
329
  }
@@ -351,9 +352,16 @@ class ExportSQLCommand {
351
352
  if (err !== null && err !== void 0 && err.message.includes('Backup Copy already in progress')) {
352
353
  await this.track('error', {
353
354
  error_type: 'job_already_running',
354
- error_message: err === null || err === void 0 ? void 0 : err.message
355
+ error_message: err === null || err === void 0 ? void 0 : err.message,
356
+ stack: err === null || err === void 0 ? void 0 : err.stack
357
+ });
358
+ exit.withError('There is an export job already running for this environment: ' + `https://dashboard.wpvip.com/apps/${this.app.id}/${this.env.uniqueLabel}/data/database/backups\n` + 'Currently, we allow only one export job at a time, per site. Please try again later.');
359
+ } else {
360
+ await this.track('error', {
361
+ error_type: 'create_export_job',
362
+ error_message: err === null || err === void 0 ? void 0 : err.message,
363
+ stack: err === null || err === void 0 ? void 0 : err.stack
355
364
  });
356
- exit.withError('There is an export job already running for this site: ' + `https://dashboard.wpvip.com/apps/${this.app.id}/${this.env.uniqueLabel}/data/database/backups\n` + 'Currently, we allow only one export job at a time, per site. Please try again later.');
357
365
  }
358
366
  exit.withError(`Error creating export job: ${err === null || err === void 0 ? void 0 : err.message}`);
359
367
  }
@@ -378,7 +386,8 @@ class ExportSQLCommand {
378
386
  this.stopProgressTracker();
379
387
  await this.track('error', {
380
388
  error_type: 'download_failed',
381
- error_message: err === null || err === void 0 ? void 0 : err.message
389
+ error_message: err === null || err === void 0 ? void 0 : err.message,
390
+ stack: err === null || err === void 0 ? void 0 : err.stack
382
391
  });
383
392
  exit.withError(`Error downloading exported file: ${err === null || err === void 0 ? void 0 : err.message}`);
384
393
  }
@@ -4,36 +4,29 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
+ var _debug = _interopRequireDefault(require("debug"));
7
8
  var _http = _interopRequireDefault(require("../../../lib/api/http"));
8
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
10
  /**
10
11
  * External dependencies
11
12
  */
12
- const debug = require('debug')('@automattic/vip:analytics:clients:pendo');
13
13
 
14
14
  /**
15
15
  * Internal dependencies
16
16
  */
17
17
 
18
+ const debug = (0, _debug.default)('@automattic/vip:analytics:clients:pendo');
18
19
  /**
19
20
  * Pendo analytics client.
20
21
  */
21
-
22
22
  class Pendo {
23
- context = {};
24
- static get ENDPOINT() {
25
- return '/pendo';
26
- }
27
- constructor({
28
- userId,
29
- eventPrefix,
30
- env
31
- }) {
32
- this.eventPrefix = eventPrefix;
33
- this.userAgent = env.userAgent;
34
- this.userId = userId;
23
+ static ENDPOINT = '/pendo';
24
+ constructor(options) {
25
+ this.eventPrefix = options.eventPrefix;
26
+ this.userAgent = options.env.userAgent;
27
+ this.userId = options.userId;
35
28
  this.context = {
36
- ...env
29
+ ...options.env
37
30
  };
38
31
  }
39
32
  async trackEvent(eventName, eventProps = {}) {
@@ -52,10 +45,8 @@ class Pendo {
52
45
  return await this.send(eventName, eventProps);
53
46
  } catch (error) {
54
47
  debug(error);
48
+ return Promise.resolve(false);
55
49
  }
56
-
57
- // Resolve to false instead of rejecting
58
- return Promise.resolve(false);
59
50
  }
60
51
  async send(eventName, eventProps) {
61
52
  const body = {
@@ -69,11 +60,11 @@ class Pendo {
69
60
  debug('send()', body);
70
61
  const response = await (0, _http.default)(Pendo.ENDPOINT, {
71
62
  method: 'POST',
72
- body
63
+ body: JSON.stringify(body)
73
64
  });
74
65
  const responseText = await response.text();
75
66
  debug('response', responseText);
76
- return responseText;
67
+ return response;
77
68
  }
78
69
  }
79
70
  exports.default = Pendo;
@@ -6,19 +6,19 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  var _nodeFetch = _interopRequireDefault(require("node-fetch"));
8
8
  var _querystring = _interopRequireDefault(require("querystring"));
9
+ var _debug = _interopRequireDefault(require("debug"));
9
10
  var _apiConfig = require("../../cli/apiConfig");
10
11
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
12
  /**
12
13
  * External dependencies
13
14
  */
14
- const debug = require('debug')('@automattic/vip:analytics:clients:tracks');
15
15
 
16
16
  /**
17
17
  * Internal dependencies
18
18
  */
19
19
 
20
+ const debug = (0, _debug.default)('@automattic/vip:analytics:clients:tracks');
20
21
  const validEventOrPropNamePattern = /^[a-z_][a-z0-9_]*$/;
21
-
22
22
  /**
23
23
  * Simple class for tracking using Automattic Tracks.
24
24
  *
@@ -28,9 +28,7 @@ const validEventOrPropNamePattern = /^[a-z_][a-z0-9_]*$/;
28
28
  // TODO: add batch support (can include multiples in `events` array)
29
29
 
30
30
  class Tracks {
31
- static get ENDPOINT() {
32
- return 'https://public-api.wordpress.com/rest/v1.1/tracks/record';
33
- }
31
+ static ENDPOINT = 'https://public-api.wordpress.com/rest/v1.1/tracks/record';
34
32
  constructor(userId, userType, eventPrefix, env) {
35
33
  this.eventPrefix = eventPrefix;
36
34
  this.userAgent = env.userAgent;
@@ -54,9 +52,10 @@ class Tracks {
54
52
  });
55
53
  eventProps.is_vip = await (0, _apiConfig.checkIfUserIsVip)(); // Add `is_vip` flag to every Tracks event recorded
56
54
 
57
- const event = Object.assign({
58
- _en: name
59
- }, eventProps);
55
+ const event = {
56
+ _en: name,
57
+ ...eventProps
58
+ };
60
59
 
61
60
  // For when we want to support batched events
62
61
  const events = [event];
@@ -89,10 +88,13 @@ class Tracks {
89
88
  }
90
89
 
91
90
  // Resolve to false instead of rejecting
92
- return Promise.resolve(false);
91
+ return false;
93
92
  }
94
93
  send(extraParams) {
95
- const params = Object.assign({}, this.baseParams, extraParams);
94
+ const params = {
95
+ ...this.baseParams,
96
+ ...extraParams
97
+ };
96
98
  const method = 'POST';
97
99
  const body = _querystring.default.stringify(params);
98
100
  const headers = {
@@ -100,8 +102,6 @@ class Tracks {
100
102
  'User-Agent': this.userAgent
101
103
  };
102
104
  debug('send()', body);
103
-
104
- // eslint-disable-next-line no-undef
105
105
  return (0, _nodeFetch.default)(Tracks.ENDPOINT, {
106
106
  method,
107
107
  body,
@@ -5,15 +5,16 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _debug = _interopRequireDefault(require("debug"));
8
- var _stub = _interopRequireDefault(require("./clients/stub"));
9
8
  var _env = _interopRequireDefault(require("../env"));
10
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
10
  /**
12
11
  * External dependencies
13
12
  */
13
+
14
14
  /**
15
15
  * Internal dependencies
16
16
  */
17
+
17
18
  const debug = (0, _debug.default)('@automattic/vip:analytics');
18
19
 
19
20
  /* eslint-disable camelcase */
@@ -26,23 +27,19 @@ const client_info = {
26
27
  /* eslint-enable camelcase */
27
28
 
28
29
  class Analytics {
29
- constructor({
30
- clients = new _stub.default()
31
- }) {
30
+ constructor(clients) {
32
31
  this.clients = clients;
33
32
  }
34
33
  async trackEvent(name, props = {}) {
35
34
  if (process.env.DO_NOT_TRACK) {
36
35
  debug(`trackEvent() for ${name} => skipping per DO_NOT_TRACK variable`);
37
- return Promise.resolve(`Skipping trackEvent for ${name} (DO_NOT_TRACK)`);
36
+ return [];
38
37
  }
39
- return Promise.all(this.clients.map(client => {
40
- return client.trackEvent(name, {
41
- // eslint-disable-next-line camelcase
42
- ...client_info,
43
- ...props
44
- });
45
- }));
38
+ return Promise.all(this.clients.map(client => client.trackEvent(name, {
39
+ // eslint-disable-next-line camelcase
40
+ ...client_info,
41
+ ...props
42
+ })));
46
43
  }
47
44
  }
48
45
  exports.default = Analytics;