@automattic/vip 2.36.3 → 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.
- package/assets/dev-env.lando.template.yml.ejs +1 -1
- package/dist/bin/vip-app-deploy.js +251 -0
- package/dist/bin/vip-app.js +1 -1
- package/dist/bin/vip-dev-env-import-sql.js +1 -1
- package/dist/bin/vip-import-sql.js +1 -1
- package/dist/commands/dev-env-import-sql.js +18 -15
- package/dist/commands/dev-env-sync-sql.js +3 -2
- package/dist/lib/cli/command.js +28 -19
- package/dist/lib/cli/exit.js +7 -2
- package/dist/lib/cli/format.js +2 -2
- package/dist/lib/client-file-uploader.js +22 -13
- package/dist/lib/constants/dev-environment.js +2 -10
- package/dist/lib/custom-deploy/custom-deploy.js +95 -0
- package/dist/lib/dev-environment/dev-environment-cli.js +4 -2
- package/dist/lib/dev-environment/dev-environment-configuration-file.js +7 -6
- package/dist/lib/dev-environment/dev-environment-core.js +20 -7
- package/dist/lib/dev-environment/docker-utils.js +1 -1
- package/dist/lib/env.js +2 -1
- package/dist/lib/user-error.js +2 -2
- package/dist/lib/validations/custom-deploy.js +39 -0
- package/dist/lib/validations/line-by-line.js +3 -1
- package/dist/lib/validations/sql.js +1 -1
- package/docs/CHANGELOG.md +44 -0
- package/npm-shrinkwrap.json +346 -698
- package/package.json +7 -5
- package/tsconfig.json +2 -2
|
@@ -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);
|
package/dist/bin/vip-app.js
CHANGED
|
@@ -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);
|
|
@@ -24,9 +24,9 @@ class DevEnvImportSQLCommand {
|
|
|
24
24
|
this.options = options;
|
|
25
25
|
this.slug = slug;
|
|
26
26
|
}
|
|
27
|
-
async run(
|
|
27
|
+
async run() {
|
|
28
28
|
const lando = await (0, _devEnvironmentLando.bootstrapLando)();
|
|
29
|
-
await (0, _devEnvironmentCli.validateDependencies)(lando, this.slug,
|
|
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
|
-
|
|
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
|
-
|
|
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 (!
|
|
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
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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(
|
|
164
|
+
await importCommand.run();
|
|
164
165
|
}
|
|
165
166
|
|
|
166
167
|
/**
|
package/dist/lib/cli/command.js
CHANGED
|
@@ -27,7 +27,7 @@ function uncaughtError(err) {
|
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
29
|
if (err instanceof _userError.default) {
|
|
30
|
-
exit.withError(err
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
507
|
+
wildcardCommand: false,
|
|
508
|
+
...opts
|
|
509
|
+
};
|
|
501
510
|
if (_opts.appContext || _opts.requireConfirm) {
|
|
502
511
|
_args.default.option('app', 'Specify the app');
|
|
503
512
|
}
|
package/dist/lib/cli/exit.js
CHANGED
|
@@ -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
|
-
|
|
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
|
}
|
package/dist/lib/cli/format.js
CHANGED
|
@@ -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
|
});
|
|
@@ -4,7 +4,7 @@ exports.__esModule = true;
|
|
|
4
4
|
exports.MULTIPART_THRESHOLD = exports.COMPRESS_THRESHOLD = void 0;
|
|
5
5
|
exports.checkFileAccess = checkFileAccess;
|
|
6
6
|
exports.detectCompressedMimeType = detectCompressedMimeType;
|
|
7
|
-
exports.
|
|
7
|
+
exports.getFileHash = void 0;
|
|
8
8
|
exports.getFileMeta = getFileMeta;
|
|
9
9
|
exports.getFileSize = getFileSize;
|
|
10
10
|
exports.getPartBoundaries = getPartBoundaries;
|
|
@@ -55,24 +55,28 @@ const MAX_CONCURRENT_PART_UPLOADS = 5;
|
|
|
55
55
|
// TODO: Replace with a proper definitions once we convert lib/cli/command.js to TypeScript
|
|
56
56
|
|
|
57
57
|
const getWorkingTempDir = () => (0, _promises.mkdtemp)(_path.default.join(_os.default.tmpdir(), 'vip-client-file-uploader'));
|
|
58
|
-
const
|
|
58
|
+
const getFileHash = async (fileName, hashType = 'md5') => {
|
|
59
59
|
const src = (0, _fs.createReadStream)(fileName);
|
|
60
|
-
const dst = (0, _crypto.createHash)(
|
|
60
|
+
const dst = (0, _crypto.createHash)(hashType);
|
|
61
61
|
try {
|
|
62
62
|
await (0, _promises2.pipeline)(src, dst);
|
|
63
63
|
return dst.digest().toString('hex');
|
|
64
64
|
} catch (err) {
|
|
65
|
-
throw new Error(`
|
|
65
|
+
throw new Error(`Could not generate file hash: ${err.message}`, {
|
|
66
|
+
cause: err
|
|
67
|
+
});
|
|
66
68
|
} finally {
|
|
67
69
|
src.close();
|
|
68
70
|
}
|
|
69
71
|
};
|
|
70
|
-
exports.
|
|
72
|
+
exports.getFileHash = getFileHash;
|
|
71
73
|
const gzipFile = async (uncompressedFileName, compressedFileName) => {
|
|
72
74
|
try {
|
|
73
75
|
await (0, _promises2.pipeline)((0, _fs.createReadStream)(uncompressedFileName), (0, _zlib.createGzip)(), (0, _fs.createWriteStream)(compressedFileName));
|
|
74
76
|
} catch (err) {
|
|
75
|
-
throw new Error(`
|
|
77
|
+
throw new Error(`Could not compress file: ${err.message}`, {
|
|
78
|
+
cause: err
|
|
79
|
+
});
|
|
76
80
|
}
|
|
77
81
|
};
|
|
78
82
|
|
|
@@ -121,13 +125,16 @@ async function uploadImportSqlFileToS3({
|
|
|
121
125
|
app,
|
|
122
126
|
env,
|
|
123
127
|
fileMeta,
|
|
124
|
-
progressCallback
|
|
128
|
+
progressCallback,
|
|
129
|
+
hashType = 'md5'
|
|
125
130
|
}) {
|
|
126
131
|
let tmpDir;
|
|
127
132
|
try {
|
|
128
133
|
tmpDir = await getWorkingTempDir();
|
|
129
134
|
} catch (err) {
|
|
130
|
-
throw new Error(`Unable to create temporary working directory: ${err.message}
|
|
135
|
+
throw new Error(`Unable to create temporary working directory: ${err.message}`, {
|
|
136
|
+
cause: err
|
|
137
|
+
});
|
|
131
138
|
}
|
|
132
139
|
debug(`File ${_chalk.default.cyan(fileMeta.basename)} is ~ ${Math.floor(fileMeta.fileSize / _fileSize.MB_IN_BYTES)} MB\n`);
|
|
133
140
|
|
|
@@ -149,9 +156,9 @@ async function uploadImportSqlFileToS3({
|
|
|
149
156
|
const calculation = `${(fewerBytes / _fileSize.MB_IN_BYTES).toFixed(2)}MB (${Math.floor(100 * fewerBytes / uncompressedFileSize)}%)`;
|
|
150
157
|
debug(`** Compression resulted in a ${calculation} smaller file 📦 **\n`);
|
|
151
158
|
}
|
|
152
|
-
debug(
|
|
153
|
-
const
|
|
154
|
-
debug(`Calculated file
|
|
159
|
+
debug(`Calculating file ${hashType} checksum...`);
|
|
160
|
+
const checksum = await getFileHash(fileMeta.fileName, hashType);
|
|
161
|
+
debug(`Calculated file ${hashType} checksum: ${checksum}\n`);
|
|
155
162
|
const result = fileMeta.fileSize < MULTIPART_THRESHOLD ? await uploadUsingPutObject({
|
|
156
163
|
app,
|
|
157
164
|
env,
|
|
@@ -165,7 +172,7 @@ async function uploadImportSqlFileToS3({
|
|
|
165
172
|
});
|
|
166
173
|
return {
|
|
167
174
|
fileMeta,
|
|
168
|
-
|
|
175
|
+
checksum,
|
|
169
176
|
result
|
|
170
177
|
};
|
|
171
178
|
}
|
|
@@ -225,7 +232,9 @@ async function uploadUsingPutObject({
|
|
|
225
232
|
try {
|
|
226
233
|
parsedResponse = await parser.parseStringPromise(result);
|
|
227
234
|
} catch (err) {
|
|
228
|
-
throw new Error(`Invalid response from cloud service. ${err.message}
|
|
235
|
+
throw new Error(`Invalid response from cloud service. ${err.message}`, {
|
|
236
|
+
cause: err
|
|
237
|
+
});
|
|
229
238
|
}
|
|
230
239
|
const {
|
|
231
240
|
Code,
|