@automattic/vip 2.37.0-dev.0 → 2.37.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.
@@ -35,7 +35,7 @@ services:
35
35
  ssl: true
36
36
  sslExpose: false
37
37
  services:
38
- image: ghcr.io/automattic/vip-container-images/nginx:1.23.3
38
+ image: ghcr.io/automattic/vip-container-images/nginx:latest
39
39
  command: nginx -g "daemon off;"
40
40
  environment:
41
41
  LANDO_NO_SCRIPTS: 1
@@ -0,0 +1,251 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * External dependencies
5
+ */
6
+ "use strict";
7
+
8
+ exports.__esModule = true;
9
+ exports.appDeployCmd = appDeployCmd;
10
+ exports.promptToContinue = promptToContinue;
11
+ var _chalk = _interopRequireDefault(require("chalk"));
12
+ var _debug = _interopRequireDefault(require("debug"));
13
+ var _enquirer = require("enquirer");
14
+ var _graphqlTag = _interopRequireDefault(require("graphql-tag"));
15
+ var _api = _interopRequireDefault(require("../lib/api"));
16
+ var _command = _interopRequireDefault(require("../lib/cli/command"));
17
+ var exit = _interopRequireWildcard(require("../lib/cli/exit"));
18
+ var _format = require("../lib/cli/format");
19
+ var _progress = require("../lib/cli/progress");
20
+ var _clientFileUploader = require("../lib/client-file-uploader");
21
+ var _customDeploy = require("../lib/custom-deploy/custom-deploy");
22
+ var _tracker = require("../lib/tracker");
23
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
24
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
25
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
26
+ /**
27
+ * Internal dependencies
28
+ */
29
+ const appQuery = `
30
+ id,
31
+ name,
32
+ type,
33
+ typeId
34
+ organization { id, name },
35
+ environments{
36
+ id
37
+ appId
38
+ type
39
+ name
40
+ launched
41
+ isK8sResident
42
+ syncProgress { status }
43
+ primaryDomain { name }
44
+ wpSites {
45
+ nodes {
46
+ homeUrl
47
+ id
48
+ }
49
+ }
50
+ }
51
+ `;
52
+ const START_DEPLOY_MUTATION = (0, _graphqlTag.default)`
53
+ mutation StartDeploy($input: AppEnvironmentDeployInput) {
54
+ startDeploy(input: $input) {
55
+ app {
56
+ id
57
+ name
58
+ }
59
+ message
60
+ success
61
+ }
62
+ }
63
+ `;
64
+ const debug = (0, _debug.default)('@automattic/vip:bin:vip-app-deploy');
65
+ const DEPLOY_PREFLIGHT_PROGRESS_STEPS = [{
66
+ id: 'upload',
67
+ name: 'Uploading file'
68
+ }, {
69
+ id: 'deploy',
70
+ name: 'Triggering deployment'
71
+ }];
72
+ /**
73
+ * Prompt the user to confirm the environment they are deploying to.
74
+ * @param {PromptToContinueParams} PromptToContinueParams
75
+ */
76
+ async function promptToContinue(params) {
77
+ const promptToMatch = params.domain.toUpperCase();
78
+ const promptResponse = await (0, _enquirer.prompt)({
79
+ type: 'input',
80
+ name: 'confirmedDomain',
81
+ message: `You are about to deploy to a ${params.launched ? 'launched' : 'un-launched'} ${params.formattedEnvironment} site ${_chalk.default.yellow(params.domain)}.\nType '${_chalk.default.yellow(promptToMatch)}' (without the quotes) to continue:\n`
82
+ });
83
+ if (promptResponse.confirmedDomain !== promptToMatch) {
84
+ await params.track('deploy_app_unexpected_input');
85
+ exit.withError('The input did not match the expected environment label. Deploy aborted.');
86
+ }
87
+ }
88
+ async function appDeployCmd(arg = [], opts = {}) {
89
+ const app = opts.app;
90
+ const env = opts.env;
91
+ const [fileName] = arg;
92
+ const fileMeta = await (0, _clientFileUploader.getFileMeta)(fileName);
93
+ const inputBasename = fileMeta.basename;
94
+ debug('Options: ', opts);
95
+ debug('Args: ', arg);
96
+ const appId = env.appId;
97
+ const envId = env.id;
98
+ const track = _tracker.trackEventWithEnv.bind(null, appId, envId);
99
+ await (0, _customDeploy.gates)(app, env, fileMeta);
100
+ await track('deploy_app_command_execute');
101
+
102
+ // Upload file as different name to avoid overwriting existing same named files
103
+ const datePrefix = new Date().toISOString()
104
+ // eslint-disable-next-line no-useless-escape
105
+ .replace(/[\-T:\.Z]/g, '').slice(0, 14);
106
+ fileMeta.basename = `${datePrefix}-${fileMeta.basename}`;
107
+ const deployMessage = opts.message ?? '';
108
+ const forceDeploy = opts.force;
109
+ const domain = env?.primaryDomain?.name ? env.primaryDomain.name : `#${env.id}`;
110
+ if (!forceDeploy) {
111
+ const promptParams = {
112
+ launched: Boolean(env.launched),
113
+ formattedEnvironment: (0, _format.formatEnvironment)(env.type),
114
+ track,
115
+ domain
116
+ };
117
+ await promptToContinue(promptParams);
118
+ }
119
+
120
+ /**
121
+ * =========== WARNING =============
122
+ *
123
+ * NO `console.log` after this point!
124
+ * Yes, even inside called functions.
125
+ * It will break the progress printing.
126
+ *
127
+ * =========== WARNING =============
128
+ */
129
+ const progressTracker = new _progress.ProgressTracker(DEPLOY_PREFLIGHT_PROGRESS_STEPS);
130
+ let status = 'running';
131
+ const setProgressTrackerPrefixAndSuffix = () => {
132
+ progressTracker.prefix = `
133
+ =============================================================
134
+ Processing the file for deployment to your environment...
135
+ `;
136
+ progressTracker.suffix = `\n${(0, _format.getGlyphForStatus)(status, progressTracker.runningSprite)} Running...`;
137
+ };
138
+ const failWithError = failureError => {
139
+ status = 'failed';
140
+ setProgressTrackerPrefixAndSuffix();
141
+ progressTracker.stopPrinting();
142
+ progressTracker.print({
143
+ clearAfter: true
144
+ });
145
+ exit.withError(failureError);
146
+ };
147
+ progressTracker.startPrinting(setProgressTrackerPrefixAndSuffix);
148
+ progressTracker.stepRunning('upload');
149
+
150
+ // Call the Public API
151
+ const api = await (0, _api.default)();
152
+ const progressCallback = percentage => {
153
+ progressTracker.setUploadPercentage(percentage);
154
+ };
155
+ const appInput = {
156
+ id: appId
157
+ };
158
+ const envInput = {
159
+ id: envId
160
+ };
161
+ const uploadParams = {
162
+ app: appInput,
163
+ env: envInput,
164
+ fileMeta,
165
+ progressCallback,
166
+ hashType: 'sha256'
167
+ };
168
+ const startDeployVariables = {
169
+ input: {}
170
+ };
171
+ try {
172
+ const {
173
+ fileMeta: {
174
+ basename
175
+ },
176
+ checksum,
177
+ result
178
+ } = await (0, _clientFileUploader.uploadImportSqlFileToS3)(uploadParams);
179
+ startDeployVariables.input = {
180
+ id: app.id,
181
+ environmentId: env.id,
182
+ basename: fileMeta.basename,
183
+ checksum,
184
+ deployMessage
185
+ };
186
+ debug({
187
+ basename,
188
+ checksum,
189
+ result,
190
+ startDeployVariables
191
+ });
192
+ debug('Upload complete. Initiating the deploy.');
193
+ progressTracker.stepSuccess('upload');
194
+ await track('deploy_app_upload_complete');
195
+ } catch (uploadError) {
196
+ await track('deploy_app_command_error', {
197
+ error_type: 'upload_failed',
198
+ upload_error: uploadError.message
199
+ });
200
+ progressTracker.stepFailed('upload');
201
+ return failWithError(uploadError);
202
+ }
203
+ progressTracker.stepRunning('deploy');
204
+
205
+ // Start the deploy
206
+ try {
207
+ const startDeployResults = await api.mutate({
208
+ mutation: START_DEPLOY_MUTATION,
209
+ variables: startDeployVariables
210
+ });
211
+ debug({
212
+ startDeployResults
213
+ });
214
+ } catch (gqlErr) {
215
+ progressTracker.stepFailed('deploy');
216
+ await track('deploy_app_command_error', {
217
+ error_type: 'StartDeploy-failed',
218
+ gql_err: gqlErr
219
+ });
220
+ progressTracker.stepFailed('deploy');
221
+ return failWithError(`StartDeploy call failed: ${gqlErr.message}`);
222
+ }
223
+ progressTracker.stepSuccess('deploy');
224
+ progressTracker.stopPrinting();
225
+ progressTracker.suffix = '';
226
+ progressTracker.print({
227
+ clearAfter: true
228
+ });
229
+ const deploymentsUrl = `https://dashboard.wpvip.com/apps/${appId}/${env.type}/code/deployments`;
230
+ console.log(`\n✅ ${_chalk.default.bold(_chalk.default.underline(_chalk.default.magenta(inputBasename)))} has been sent for deployment to ${_chalk.default.bold(_chalk.default.blue(domain))}. \nTo check deployment status, go to ${_chalk.default.bold('VIP Dashboard')}: ${deploymentsUrl}`);
231
+ }
232
+
233
+ // Command examples for the `vip deploy app` help prompt
234
+ const examples = [
235
+ // `app` subcommand
236
+ {
237
+ usage: 'vip app @mysite.develop deploy file.zip',
238
+ description: 'Deploy the given compressed file to your site'
239
+ }, {
240
+ usage: 'vip app @mysite.develop deploy file.zip --message "This is a deploy message"',
241
+ description: 'Deploy the given compressed file to your site'
242
+ }, {
243
+ usage: 'vip app @mysite.develop deploy file.zip --force',
244
+ description: 'Deploy the given compressed file to your site without prompting'
245
+ }];
246
+ void (0, _command.default)({
247
+ appContext: true,
248
+ appQuery,
249
+ envContext: true,
250
+ requiredArgs: 1
251
+ }).examples(examples).option('message', 'Custom message for deploy').option('force', 'Skip prompt').argv(process.argv, appDeployCmd);
@@ -11,7 +11,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
11
11
  (0, _command.default)({
12
12
  requiredArgs: 1,
13
13
  format: true
14
- }).example('vip app <app>', 'Pass an app name or ID to get details about that app').example('vip app 123', 'Get details about the app with ID 123').example('vip app vip-test', 'Get details about the app named vip-test').command('list', 'List your VIP applications').argv(process.argv, async arg => {
14
+ }).example('vip app <app>', 'Pass an app name or ID to get details about that app').example('vip app 123', 'Get details about the app with ID 123').example('vip app vip-test', 'Get details about the app named vip-test').example('vip app @mysite.develop deploy <file.zip>', 'Deploy the given compressed file to your site').command('list', 'List your VIP applications').command('deploy', 'Deploy to your app from a file').argv(process.argv, async arg => {
15
15
  await (0, _tracker.trackEvent)('app_command_execute');
16
16
  let res;
17
17
  try {
@@ -22,7 +22,7 @@ const examples = [{
22
22
  }];
23
23
  (0, _command.default)({
24
24
  requiredArgs: 1
25
- }).option('slug', 'Custom name of the dev environment').option(['r', 'search-replace'], 'Perform Search and Replace on the specified SQL file').option('in-place', 'Search and Replace explicitly on the given input file').option('skip-validate', 'Do not perform file validation.').examples(examples).argv(process.argv, async (unmatchedArgs, opt) => {
25
+ }).option('slug', 'Custom name of the dev environment').option(['r', 'search-replace'], 'Perform Search and Replace on the specified SQL file').option('in-place', 'Search and Replace explicitly on the given input file').option('skip-validate', 'Do not perform file validation').option(['k', 'skip-reindex'], 'Do not reindex data in Elasticsearch after import').option('quiet', 'Suppress prompts and informational messages').examples(examples).argv(process.argv, async (unmatchedArgs, opt) => {
26
26
  const [fileName] = unmatchedArgs;
27
27
  const slug = await (0, _devEnvironmentCli.getEnvironmentName)(opt);
28
28
  const cmd = new _devEnvImportSql.DevEnvImportSQLCommand(fileName, opt, slug);
@@ -460,7 +460,7 @@ Processing the SQL import for your environment...
460
460
  fileMeta: {
461
461
  basename
462
462
  },
463
- md5,
463
+ checksum: md5,
464
464
  result
465
465
  } = await (0, _clientFileUploader.uploadImportSqlFileToS3)({
466
466
  app,
package/dist/bin/vip.js CHANGED
@@ -21,7 +21,7 @@ if (_config.default && _config.default.environment !== 'production') {
21
21
  const tokenURL = 'https://dashboard.wpvip.com/me/cli/token';
22
22
  const runCmd = async function () {
23
23
  const cmd = (0, _command.default)();
24
- cmd.command('logout', 'Logout from your current session').command('app', 'List and modify your VIP applications').command('backup', 'Generate a backup for VIP applications').command('cache', 'Manage page cache for your VIP applications').command('config', 'Set configuration for your VIP applications').command('dev-env', 'Use local dev-environment').command('export', 'Export data from your VIP application').command('import', 'Import media or SQL files into your VIP applications').command('logs', 'Get logs from your VIP applications').command('search-replace', 'Perform search and replace tasks on files').command('slowlogs', 'Get slowlogs from your VIP applications').command('db', 'Run operations on your VIP application database').command('sync', 'Sync production to a development environment').command('whoami', 'Display details about the currently logged-in user').command('validate', 'Validate your VIP application and environment').command('wp', 'Run WP CLI commands against an environment');
24
+ cmd.command('logout', 'Logout from your current session').command('app', 'List and modify your VIP applications').command('backup', 'Generate a backup for VIP applications').command('cache', 'Manage page cache for your VIP applications').command('config', 'Set configuration for your VIP applications').command('dev-env', 'Use local dev-environment').command('export', 'Export data from your VIP application').command('import', 'Import media or SQL files into your VIP applications').command('logs', 'Get logs from your VIP applications').command('search-replace', 'Perform search and replace tasks on files').command('slowlogs', 'Get slowlogs from your VIP applications').command('sync', 'Sync production to a development environment').command('whoami', 'Display details about the currently logged-in user').command('validate', 'Validate your VIP application and environment').command('wp', 'Run WP CLI commands against an environment');
25
25
  cmd.argv(process.argv);
26
26
  };
27
27
 
@@ -24,9 +24,9 @@ class DevEnvImportSQLCommand {
24
24
  this.options = options;
25
25
  this.slug = slug;
26
26
  }
27
- async run(silent = false) {
27
+ async run() {
28
28
  const lando = await (0, _devEnvironmentLando.bootstrapLando)();
29
- await (0, _devEnvironmentCli.validateDependencies)(lando, this.slug, silent);
29
+ await (0, _devEnvironmentCli.validateDependencies)(lando, this.slug, this.options.quiet);
30
30
  (0, _sql.validateImportFileExtension)(this.fileName);
31
31
 
32
32
  // Check if file is compressed and if so, extract the
@@ -35,9 +35,13 @@ class DevEnvImportSQLCommand {
35
35
  const tmpDir = (0, _utils.makeTempDir)();
36
36
  const sqlFile = `${tmpDir}/sql-import.sql`;
37
37
  try {
38
- console.log(`Extracting the compressed file ${this.fileName}...`);
38
+ if (!this.options.quiet) {
39
+ console.log(`Extracting the compressed file ${this.fileName}...`);
40
+ }
39
41
  await (0, _clientFileUploader.unzipFile)(this.fileName, sqlFile);
40
- console.log(`${_chalk.default.green('✓')} Extracted to ${sqlFile}`);
42
+ if (!this.options.quiet) {
43
+ console.log(`${_chalk.default.green('✓')} Extracted to ${sqlFile}`);
44
+ }
41
45
  this.fileName = sqlFile;
42
46
  } catch (err) {
43
47
  exit.withError(`Error extracting the SQL file: ${err.message}`);
@@ -62,7 +66,7 @@ class DevEnvImportSQLCommand {
62
66
  });
63
67
  }
64
68
  const fd = await _fs.default.promises.open(resolvedPath, 'r');
65
- const importArg = ['db', '--disable-auto-rehash'];
69
+ const importArg = ['db', '--disable-auto-rehash'].concat(this.options.quiet ? '--silent' : []);
66
70
  const origIsTTY = process.stdin.isTTY;
67
71
  try {
68
72
  /**
@@ -76,27 +80,26 @@ class DevEnvImportSQLCommand {
76
80
  await (0, _devEnvironmentCore.exec)(lando, this.slug, importArg, {
77
81
  stdio: [fd, 'pipe', 'pipe']
78
82
  });
79
- if (!silent) {
83
+ if (!this.options.quiet) {
80
84
  console.log(`${_chalk.default.green.bold('Success:')} Database imported.`);
81
85
  }
82
86
  } finally {
83
87
  process.stdin.isTTY = origIsTTY;
84
88
  }
85
- if (searchReplace && searchReplace.length && !inPlace) {
89
+ if (searchReplace?.length && !inPlace) {
86
90
  _fs.default.unlinkSync(resolvedPath);
87
91
  }
88
- const cacheArg = ['wp', 'cache', 'flush'];
92
+ const cacheArg = ['wp', 'cache', 'flush'].concat(this.options.quiet ? '--quiet' : []);
89
93
  await (0, _devEnvironmentCore.exec)(lando, this.slug, cacheArg);
90
- try {
91
- await (0, _devEnvironmentCore.exec)(lando, this.slug, ['wp', 'cli', 'has-command', 'vip-search']);
92
- const doIndex = await (0, _devEnvironmentCli.promptForBoolean)('Do you want to index data in Elasticsearch (used by Enterprise Search)?', true);
93
- if (doIndex) {
94
+ if (undefined === this.options.skipReindex || !(0, _devEnvironmentCli.processBooleanOption)(this.options.skipReindex)) {
95
+ try {
96
+ await (0, _devEnvironmentCore.exec)(lando, this.slug, ['wp', 'cli', 'has-command', 'vip-search']);
94
97
  await (0, _devEnvironmentCore.exec)(lando, this.slug, ['wp', 'vip-search', 'index', '--setup', '--network-wide', '--skip-confirm']);
98
+ } catch {
99
+ // Exception means they don't have vip-search enabled.
95
100
  }
96
- } catch (err) {
97
- // Exception means they don't have vip-search enabled.
98
101
  }
99
- const addUserArg = ['wp', 'dev-env-add-admin', '--username=vipgo', '--password=password'];
102
+ const addUserArg = ['wp', 'dev-env-add-admin', '--username=vipgo', '--password=password'].concat(this.options.quiet ? '--quiet' : []);
100
103
  await (0, _devEnvironmentCore.exec)(lando, this.slug, addUserArg);
101
104
  }
102
105
  }
@@ -157,10 +157,11 @@ class DevEnvSyncSQLCommand {
157
157
  async runImport() {
158
158
  const importOptions = {
159
159
  inPlace: true,
160
- skipValidate: true
160
+ skipValidate: true,
161
+ quiet: true
161
162
  };
162
163
  const importCommand = new _devEnvImportSql.DevEnvImportSQLCommand(this.sqlFile, importOptions, this.slug);
163
- await importCommand.run(true);
164
+ await importCommand.run();
164
165
  }
165
166
 
166
167
  /**
@@ -27,7 +27,7 @@ function uncaughtError(err) {
27
27
  return;
28
28
  }
29
29
  if (err instanceof _userError.default) {
30
- exit.withError(err.message);
30
+ exit.withError(err);
31
31
  }
32
32
  console.log(_chalk.default.red('✕'), 'Please contact VIP Support with the following information:');
33
33
  console.log(_chalk.default.dim(err.stack));
@@ -182,7 +182,7 @@ _args.default.argv = async function (argv, cb) {
182
182
  });
183
183
  exit.withError(`Failed to get app (${_opts.appQuery}) details: ${message}`);
184
184
  }
185
- if (!res || !res.data || !res.data.apps || !res.data.apps.edges || !res.data.apps.edges.length) {
185
+ if (!res.data?.apps?.edges?.length) {
186
186
  await (0, _tracker.trackEvent)('command_appcontext_list_fetch_error', {
187
187
  error: 'No apps found'
188
188
  });
@@ -207,14 +207,16 @@ _args.default.argv = async function (argv, cb) {
207
207
 
208
208
  // Copy all app information
209
209
  appSelection.app = res.data.apps.edges.find(cur => cur.name === appSelection.app);
210
- if (!appSelection || !appSelection.app || !appSelection.app.id) {
210
+ if (!appSelection.app?.id) {
211
211
  await (0, _tracker.trackEvent)('command_appcontext_list_select_error', {
212
212
  error: 'Invalid app selected'
213
213
  });
214
214
  exit.withError(`App ${_chalk.default.blueBright(appSelection.app.name)} does not exist`);
215
215
  }
216
216
  await (0, _tracker.trackEvent)('command_appcontext_list_select_success');
217
- options.app = Object.assign({}, appSelection.app);
217
+ options.app = {
218
+ ...appSelection.app
219
+ };
218
220
  } else {
219
221
  let appLookup;
220
222
  try {
@@ -225,14 +227,16 @@ _args.default.argv = async function (argv, cb) {
225
227
  });
226
228
  exit.withError(`App ${_chalk.default.blueBright(options.app)} does not exist`);
227
229
  }
228
- if (!appLookup || !appLookup.id) {
230
+ if (!appLookup?.id) {
229
231
  await (0, _tracker.trackEvent)('command_appcontext_param_error', {
230
232
  error: 'Invalid app specified'
231
233
  });
232
234
  exit.withError(`App ${_chalk.default.blueBright(options.app)} does not exist`);
233
235
  }
234
236
  await (0, _tracker.trackEvent)('command_appcontext_param_select');
235
- options.app = Object.assign({}, appLookup);
237
+ options.app = {
238
+ ...appLookup
239
+ };
236
240
  }
237
241
  if (_opts.childEnvContext) {
238
242
  options.app.environments = options.app.environments.filter(cur => cur.id !== options.app.id);
@@ -254,7 +258,7 @@ _args.default.argv = async function (argv, cb) {
254
258
  exit.withError(`Environment ${_chalk.default.blueBright(options.env)} for app ${_chalk.default.blueBright(options.app.name)} does not exist`);
255
259
  }
256
260
  options.env = env;
257
- } else if (!options.app || !options.app.environments || !options.app.environments.length) {
261
+ } else if (!options.app?.environments?.length) {
258
262
  console.log('To set up a new development environment, please contact VIP Support.');
259
263
  await (0, _tracker.trackEvent)('command_childcontext_fetch_error', {
260
264
  error: 'No child environments found'
@@ -281,7 +285,7 @@ _args.default.argv = async function (argv, cb) {
281
285
 
282
286
  // Get full environment info after user selection
283
287
  envSelection.env = options.app.environments.find(envObject => getEnvIdentifier(envObject) === envSelection.env);
284
- if (!envSelection || !envSelection.env || !envSelection.env.id) {
288
+ if (!envSelection.env?.id) {
285
289
  await (0, _tracker.trackEvent)('command_childcontext_list_select_error', {
286
290
  error: 'Invalid environment selected'
287
291
  });
@@ -317,7 +321,7 @@ _args.default.argv = async function (argv, cb) {
317
321
  case 'import-sql':
318
322
  {
319
323
  const site = options.env;
320
- if (site && site.primaryDomain) {
324
+ if (site?.primaryDomain) {
321
325
  const primaryDomainName = site.primaryDomain.name;
322
326
  info.push({
323
327
  key: 'Primary Domain Name',
@@ -326,7 +330,7 @@ _args.default.argv = async function (argv, cb) {
326
330
  }
327
331
 
328
332
  // Site launched details
329
- const haveLaunchedField = Object.prototype.hasOwnProperty.call(site, 'launched');
333
+ const haveLaunchedField = Object.hasOwn(site, 'launched');
330
334
  if (haveLaunchedField) {
331
335
  const launched = site.launched ? '✅ Yes' : `${_chalk.default.red('x')} No`;
332
336
  info.push({
@@ -340,7 +344,7 @@ _args.default.argv = async function (argv, cb) {
340
344
  value: `${_chalk.default.blueBright(this.sub)}`
341
345
  });
342
346
  }
343
- options.skipValidate = Object.prototype.hasOwnProperty.call(options, 'skipValidate') && Boolean(options.skipValidate) && !['false', 'no'].includes(options.skipValidate);
347
+ options.skipValidate = Object.hasOwn(options, 'skipValidate') && Boolean(options.skipValidate) && !['false', 'no'].includes(options.skipValidate);
344
348
  if (options.skipValidate) {
345
349
  info.push({
346
350
  key: 'Pre-Upload Validations',
@@ -410,17 +414,17 @@ _args.default.argv = async function (argv, cb) {
410
414
  key: 'Archive URL',
411
415
  value: _chalk.default.blue.underline(this.sub)
412
416
  });
413
- options.overwriteExistingFiles = Object.prototype.hasOwnProperty.call(options, 'overwriteExistingFiles') && Boolean(options.overwriteExistingFiles) && !['false', 'no'].includes(options.overwriteExistingFiles);
417
+ options.overwriteExistingFiles = Object.hasOwn(options, 'overwriteExistingFiles') && Boolean(options.overwriteExistingFiles) && !['false', 'no'].includes(options.overwriteExistingFiles);
414
418
  info.push({
415
419
  key: 'Overwrite any existing files',
416
420
  value: options.overwriteExistingFiles ? '✅ Yes' : `${_chalk.default.red('x')} No`
417
421
  });
418
- options.importIntermediateImages = Object.prototype.hasOwnProperty.call(options, 'importIntermediateImages') && Boolean(options.importIntermediateImages) && !['false', 'no'].includes(options.importIntermediateImages);
422
+ options.importIntermediateImages = Object.hasOwn(options, 'importIntermediateImages') && Boolean(options.importIntermediateImages) && !['false', 'no'].includes(options.importIntermediateImages);
419
423
  info.push({
420
424
  key: 'Import intermediate image files',
421
425
  value: options.importIntermediateImages ? '✅ Yes' : `${_chalk.default.red('x')} No`
422
426
  });
423
- options.exportFileErrorsToJson = Object.prototype.hasOwnProperty.call(options, 'exportFileErrorsToJson') && Boolean(options.exportFileErrorsToJson) && !['false', 'no'].includes(options.exportFileErrorsToJson);
427
+ options.exportFileErrorsToJson = Object.hasOwn(options, 'exportFileErrorsToJson') && Boolean(options.exportFileErrorsToJson) && !['false', 'no'].includes(options.exportFileErrorsToJson);
424
428
  info.push({
425
429
  key: 'Export any file errors encountered to a JSON file instead of a plain text file',
426
430
  value: options.exportFileErrorsToJson ? '✅ Yes' : `${_chalk.default.red('x')} No`
@@ -440,11 +444,15 @@ _args.default.argv = async function (argv, cb) {
440
444
  res = await cb(this.sub, options);
441
445
  if (_opts.format && res) {
442
446
  if (res.header) {
443
- console.log((0, _format.formatData)(res.header, 'keyValue'));
447
+ if (options.format !== 'json') {
448
+ console.log((0, _format.formatData)(res.header, 'keyValue'));
449
+ }
444
450
  res = res.data;
445
451
  }
446
452
  res = res.map(row => {
447
- const out = Object.assign({}, row);
453
+ const out = {
454
+ ...row
455
+ };
448
456
  if (out.__typename) {
449
457
  // Apollo injects __typename
450
458
  delete out.__typename;
@@ -488,7 +496,7 @@ function validateOpts(opts) {
488
496
  * @returns {args}
489
497
  */
490
498
  function _default(opts) {
491
- _opts = Object.assign({
499
+ _opts = {
492
500
  appContext: false,
493
501
  appQuery: 'id,name',
494
502
  childEnvContext: false,
@@ -496,8 +504,9 @@ function _default(opts) {
496
504
  format: false,
497
505
  requireConfirm: false,
498
506
  requiredArgs: 0,
499
- wildcardCommand: false
500
- }, opts);
507
+ wildcardCommand: false,
508
+ ...opts
509
+ };
501
510
  if (_opts.appContext || _opts.requireConfirm) {
502
511
  _args.default.option('app', 'Specify the app');
503
512
  }
@@ -3,14 +3,19 @@
3
3
  exports.__esModule = true;
4
4
  exports.withError = withError;
5
5
  var _chalk = require("chalk");
6
+ var _debug = _interopRequireDefault(require("debug"));
6
7
  var _env = _interopRequireDefault(require("../../lib/env"));
7
8
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
8
9
  function withError(message) {
9
- console.error(`${(0, _chalk.red)('Error: ')} ${message.toString().replace(/^Error:\s*/, '')}`);
10
+ const msg = message instanceof Error ? message.message : message;
11
+ console.error(`${(0, _chalk.red)('Error: ')} ${msg.replace(/^Error:\s*/, '')}`);
10
12
 
11
13
  // Debug ouput is printed below error output both for information
12
14
  // hierarchy and to make it more likely that the user copies it to their
13
15
  // clipboard when dragging across output.
14
- console.log(`${(0, _chalk.yellow)('Debug: ')} VIP-CLI v${_env.default.app.version}, Node ${_env.default.node.version}, ${_env.default.os.name} ${_env.default.os.version}`);
16
+ console.log(`${(0, _chalk.yellow)('Debug: ')} VIP-CLI v${_env.default.app.version}, Node ${_env.default.node.version}, ${_env.default.os.name} ${_env.default.os.version} ${_env.default.os.arch}`);
17
+ if (_debug.default.names.length > 0 && message instanceof Error) {
18
+ console.error((0, _chalk.yellow)('Debug: '), message);
19
+ }
15
20
  process.exit(1);
16
21
  }
@@ -105,10 +105,10 @@ function keyValue(values) {
105
105
  function requoteArgs(args) {
106
106
  return args.map(arg => {
107
107
  if (arg.includes('--') && arg.includes('=') && arg.includes(' ')) {
108
- return arg.replace(/^--([^=]*)=(.*)$/, '--$1="$2"');
108
+ return arg.replace(/"/g, '\\"').replace(/^--([^=]*)=(.*)$/, '--$1="$2"');
109
109
  }
110
110
  if (arg.includes(' ') && !isJsonObject(arg)) {
111
- return `"${arg}"`;
111
+ return `"${arg.replace(/"/g, '\\"')}"`;
112
112
  }
113
113
  return arg;
114
114
  });