@automattic/vip 2.31.1-dev → 2.31.1-dev3
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/.editorconfig +11 -0
- package/.prettierignore +6 -0
- package/CONTRIBUTING.md +20 -19
- package/dist/bin/vip-app-list.js +12 -10
- package/dist/bin/vip-dev-env-start.js +4 -1
- package/dist/bin/vip-dev-env-sync-sql.js +1 -1
- package/dist/bin/vip-export-sql.js +3 -2
- package/dist/bin/vip-import-media-abort.js +3 -3
- package/dist/bin/vip-import-media.js +3 -3
- package/dist/bin/vip-import-sql.js +2 -1
- package/dist/bin/vip-sync.js +27 -13
- package/dist/bin/vip-validate-preflight.js +16 -14
- package/dist/bin/vip-wp.js +9 -9
- package/dist/commands/backup-db.js +30 -26
- package/dist/commands/export-sql.js +2 -3
- package/dist/lib/api/cache-purge.js +2 -10
- package/dist/lib/app-logs/app-logs.js +10 -4
- package/dist/lib/cli/format.js +2 -2
- package/dist/lib/config/software.js +10 -9
- package/dist/lib/constants/dev-environment.js +3 -6
- package/dist/lib/dev-environment/dev-environment-cli.js +3 -3
- package/dist/lib/dev-environment/dev-environment-core.js +52 -41
- package/dist/lib/dev-environment/dev-environment-lando.js +3 -1
- package/dist/lib/envvar/api-delete.js +2 -11
- package/dist/lib/envvar/api-get-all.js +3 -10
- package/dist/lib/envvar/api-list.js +3 -10
- package/dist/lib/envvar/api-set.js +2 -12
- package/dist/lib/media-import/status.js +18 -18
- package/dist/lib/validations/site-type.js +1 -1
- package/dist/lib/validations/sql.js +2 -1
- package/dist/lib/vip-import-validate-files.js +1 -0
- package/helpers/check-version.js +7 -5
- package/helpers/prepublishOnly.js +90 -0
- package/npm-shrinkwrap.json +238 -3936
- package/package.json +12 -12
- package/tsconfig.json +5 -9
- package/automattic-vip-2.31.1-dev.tgz +0 -0
package/.editorconfig
ADDED
package/.prettierignore
ADDED
package/CONTRIBUTING.md
CHANGED
|
@@ -35,35 +35,38 @@ Who doesn't like a good console.log for debugging?
|
|
|
35
35
|
Well, sometimes it's insufficient, luckily it's not too complicated to use a debugger.
|
|
36
36
|
|
|
37
37
|
1. First, make sure to run the `npm run build:watch`, this will generate source maps
|
|
38
|
-
2. Run the command you want via `node --inspect`, like so:
|
|
38
|
+
2. Run the command you want via `node --inspect`, like so: `node --inspect ./dist/bin/vip-dev-env-import-sql.js`
|
|
39
39
|
3. Note the port the debugger is listening on:
|
|
40
|
+
|
|
40
41
|
```
|
|
41
42
|
Debugger listening on ws://127.0.0.1:9229/db6c03e9-2585-4a08-a1c6-1fee0295c9ff
|
|
42
43
|
For help, see: https://nodejs.org/en/docs/inspector
|
|
43
44
|
```
|
|
45
|
+
|
|
44
46
|
4. In your editor of choice attach to the debugger. For VSCode: Hit 'Run and Debug' panel, hit the "gear" icon (open launch.json), make your `Attach` configuration entry to look like so:
|
|
45
|
-
Make sure the `port` matches the port from step 3, and the `runtimeExecutable` matches the exact `node` executable you ran. If you use a version manager like `nvm`, its especially important to check this.
|
|
47
|
+
Make sure the `port` matches the port from step 3, and the `runtimeExecutable` matches the exact `node` executable you ran. If you use a version manager like `nvm`, its especially important to check this.
|
|
46
48
|
|
|
47
49
|
```json
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
{
|
|
51
|
+
"name": "Attach",
|
|
52
|
+
"port": 9229,
|
|
53
|
+
"request": "attach",
|
|
54
|
+
"skipFiles": [ "<node_internals>/**" ],
|
|
55
|
+
"type": "node",
|
|
56
|
+
"runtimeExecutable": "/Users/user/.nvm/versions/node/v14.18.2/bin/node"
|
|
57
|
+
}
|
|
56
58
|
```
|
|
57
59
|
|
|
58
60
|
5. Set your breakpoints and whatnot, hit the play button.
|
|
59
61
|
6. Confirm that you attached the debugger to continue command execution
|
|
60
62
|
7. Squash them bugs 🐛🔨.
|
|
61
63
|
8. [Optional but recommended] Pay it forward and implement a similar approach to other internal/external tooling.
|
|
64
|
+
|
|
62
65
|
### Adding commands
|
|
63
66
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
- New command names should use the singular form (e.g. site vs sites).
|
|
68
|
+
- Add new commands to `package.json#bin`.
|
|
69
|
+
- Run `npm link` so that `arg` knows how to spawn the command locally. (Skipping this step will result in `Error: spawn vip-command ENOENT`.)
|
|
67
70
|
|
|
68
71
|
### Adding libraries
|
|
69
72
|
|
|
@@ -83,13 +86,14 @@ Our release flow for VIP CLI follows this pattern:
|
|
|
83
86
|
- Finally, release your changes as a new minor or major NPM version. Ping in the #vip-platform channel to notify folks of a new release, but please feel free to release your changes without any blockers from the team. Any team member that is part of the Automattic NPM organization can release a new version; if you aren't a member, generic credentials are available in the Secret Store.
|
|
84
87
|
|
|
85
88
|
### Changelogs
|
|
89
|
+
|
|
86
90
|
Changelogs allow customers to keep up with all the changes happening across our VIP Platform. Changelogs for VIP CLI are posted to the [VIP Cloud Changelog P2](https://wpvipchangelog.wordpress.com/), along with the repository’s `README.md`.
|
|
87
91
|
|
|
88
92
|
## Releasing / Publishing
|
|
89
93
|
|
|
90
94
|
### Pre-publish Checks
|
|
91
95
|
|
|
92
|
-
We use [
|
|
96
|
+
We use a custom pre-publish [script](https://github.com/Automattic/vip/blob/trunk/hellpers/prepublishOnly.js) that performs some confidence checks to avoid common mistakes.
|
|
93
97
|
|
|
94
98
|
Further checks can be added to this flow as needed.
|
|
95
99
|
|
|
@@ -126,7 +130,7 @@ Then, let's publish:
|
|
|
126
130
|
1. Push the tag to GitHub (`git push --tags`)
|
|
127
131
|
1. Push the trunk branch `git push`
|
|
128
132
|
1. Make sure you're part of the Automattic organization in npm
|
|
129
|
-
1. Publish the release to npm (`npm
|
|
133
|
+
1. Publish the release to npm (`npm publish --access public`) the script will do some extra checks (node version, branch, etc) to ensure everything is correct. If all looks good, the new version will be published and you can proceed.
|
|
130
134
|
1. Edit [the release on GitHub](https://github.com/Automattic/vip/releases) to include a description of the changes and publish (this can just copy the details from the changelog).
|
|
131
135
|
1. Push `trunk` changes (mostly the version bump) to `develop` (`git checkout develop && git merge trunk` )
|
|
132
136
|
|
|
@@ -139,10 +143,7 @@ Sometimes, we want to release a version we can test before releasing it to the p
|
|
|
139
143
|
In order to do that, please follow this:
|
|
140
144
|
|
|
141
145
|
1. Manually change the version in `package.json` and `package-lock.json` to a dev version. Example: `1.4.0-dev1`
|
|
142
|
-
|
|
143
|
-
3. Change the `publishTag` to `next` and `gitTag` to `false` (publish-please will expect the latest commit to have a git tag, but we don't want it in this case)
|
|
144
|
-
4. Commit your changes to `trunk`
|
|
145
|
-
5. Run `npm run publish-please`
|
|
146
|
+
1. Run `npm publish --tag next` (When `--tag` is specified, we bypass the usual branch protection that doesn't allow you to publish form a brunch other than `trunk`).
|
|
146
147
|
|
|
147
148
|
You can repeat this with every new version until you're happy with your version and ready to a public release. We currently don't support multiple branches for multiple versions. When it's the case, this process needs to be done for every version in every branch.
|
|
148
149
|
|
package/dist/bin/vip-app-list.js
CHANGED
|
@@ -21,17 +21,19 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
21
21
|
try {
|
|
22
22
|
response = await api.query({
|
|
23
23
|
// $FlowFixMe: gql template is not supported by flow
|
|
24
|
-
query: (0, _graphqlTag.default)`
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
query: (0, _graphqlTag.default)`
|
|
25
|
+
query Apps($first: Int, $after: String) {
|
|
26
|
+
apps(first: $first, after: $after) {
|
|
27
|
+
total
|
|
28
|
+
nextCursor
|
|
29
|
+
edges {
|
|
30
|
+
id
|
|
31
|
+
name
|
|
32
|
+
repo
|
|
33
33
|
}
|
|
34
|
-
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
`,
|
|
35
37
|
variables: {
|
|
36
38
|
first: 100,
|
|
37
39
|
after: null // TODO make dynamic
|
|
@@ -30,8 +30,11 @@ const dockerWindowsPathCmd = 'wsl -d docker-desktop bash -c "sysctl -w vm.max_ma
|
|
|
30
30
|
const examples = [{
|
|
31
31
|
usage: `${_devEnvironment.DEV_ENVIRONMENT_FULL_COMMAND} start`,
|
|
32
32
|
description: 'Starts a local dev environment'
|
|
33
|
+
}, {
|
|
34
|
+
usage: `${_devEnvironment.DEV_ENVIRONMENT_FULL_COMMAND} start --vscode`,
|
|
35
|
+
description: 'Start a local environment and generate a Workspace file for developing in Visual Studio Code'
|
|
33
36
|
}];
|
|
34
|
-
(0, _command.default)().option('slug', 'Custom name of the dev environment').option('skip-rebuild', 'Only start stopped services').option(['w', 'skip-wp-versions-check'], 'Skip
|
|
37
|
+
(0, _command.default)().option('slug', 'Custom name of the dev environment').option('skip-rebuild', 'Only start stopped services').option(['w', 'skip-wp-versions-check'], 'Skip prompt to update WordPress version if not on latest').option('vscode', 'Generate a Visual Studio Code Workspace file').examples(examples).argv(process.argv, async (arg, opt) => {
|
|
35
38
|
const slug = await (0, _devEnvironmentCli.getEnvironmentName)(opt);
|
|
36
39
|
const lando = await (0, _devEnvironmentLando.bootstrapLando)();
|
|
37
40
|
await (0, _devEnvironmentCli.validateDependencies)(lando, slug);
|
|
@@ -24,7 +24,7 @@ var _tracker = require("../lib/tracker");
|
|
|
24
24
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
25
25
|
const examples = [{
|
|
26
26
|
usage: `${_devEnvironment.DEV_ENVIRONMENT_FULL_COMMAND} sync sql @my-test.develop --slug=my_site`,
|
|
27
|
-
description:
|
|
27
|
+
description: "Syncs with the `my-test` site's `develop` environment database into `my_site`"
|
|
28
28
|
}];
|
|
29
29
|
const appQuery = `
|
|
30
30
|
id,
|
|
@@ -46,7 +46,7 @@ const appQuery = `
|
|
|
46
46
|
module: 'export-sql',
|
|
47
47
|
requiredArgs: 0,
|
|
48
48
|
usage: 'vip export sql'
|
|
49
|
-
}).option('output', 'Specify the location where you want to save the export file').option('generate-backup', '
|
|
49
|
+
}).option('output', 'Specify the location where you want to save the export file').option('generate-backup', 'Exports a freshly created database backup instead of using the latest existing one').examples(examples).argv(process.argv, async (arg, {
|
|
50
50
|
app,
|
|
51
51
|
env,
|
|
52
52
|
output,
|
|
@@ -54,7 +54,8 @@ const appQuery = `
|
|
|
54
54
|
}) => {
|
|
55
55
|
const trackerFn = (0, _tracker.makeCommandTracker)('export_sql', {
|
|
56
56
|
app: app.id,
|
|
57
|
-
env: env.uniqueLabel
|
|
57
|
+
env: env.uniqueLabel,
|
|
58
|
+
generate_backup: generateBackup
|
|
58
59
|
});
|
|
59
60
|
await trackerFn('execute');
|
|
60
61
|
const exportCommand = new _exportSql.ExportSQLCommand(app, env, {
|
|
@@ -41,8 +41,8 @@ const appQuery = `
|
|
|
41
41
|
}
|
|
42
42
|
`;
|
|
43
43
|
const ABORT_IMPORT_MUTATION = (0, _graphqlTag.default)`
|
|
44
|
-
mutation AbortMediaImport(
|
|
45
|
-
abortMediaImport(
|
|
44
|
+
mutation AbortMediaImport($input: AppEnvironmentAbortMediaImportInput) {
|
|
45
|
+
abortMediaImport(input: $input) {
|
|
46
46
|
applicationId
|
|
47
47
|
environmentId
|
|
48
48
|
mediaImportStatusChange {
|
|
@@ -60,7 +60,7 @@ const ABORT_IMPORT_MUTATION = (0, _graphqlTag.default)`
|
|
|
60
60
|
envContext: true,
|
|
61
61
|
requiredArgs: 0,
|
|
62
62
|
requireConfirm: `
|
|
63
|
-
${_chalk.default.red.bold(
|
|
63
|
+
${_chalk.default.red.bold("By running this command, the Media Import running on your App will stop and can't be resumed.")}
|
|
64
64
|
${_chalk.default.red.bold('Are you sure you want to abort this Media Import?')}
|
|
65
65
|
`
|
|
66
66
|
}).argv(process.argv, async (arg, {
|
|
@@ -38,8 +38,8 @@ const appQuery = `
|
|
|
38
38
|
}
|
|
39
39
|
`;
|
|
40
40
|
const START_IMPORT_MUTATION = (0, _graphqlTag.default)`
|
|
41
|
-
mutation StartMediaImport(
|
|
42
|
-
startMediaImport(
|
|
41
|
+
mutation StartMediaImport($input: AppEnvironmentStartMediaImportInput) {
|
|
42
|
+
startMediaImport(input: $input) {
|
|
43
43
|
applicationId
|
|
44
44
|
environmentId
|
|
45
45
|
mediaImportStatus {
|
|
@@ -83,7 +83,7 @@ function isSupportedUrl(urlToTest) {
|
|
|
83
83
|
module: 'import-media',
|
|
84
84
|
requiredArgs: 1,
|
|
85
85
|
requireConfirm: `
|
|
86
|
-
${_chalk.default.red.bold(
|
|
86
|
+
${_chalk.default.red.bold("NOTE: If the provided archive's directory structure contains an `uploads/` directory,")}
|
|
87
87
|
${_chalk.default.red.bold('only the files present inside that directory will be imported and the rest will be ignored.')}
|
|
88
88
|
${_chalk.default.red.bold('If no `uploads/` directory is found, all files will be imported, as is.')}
|
|
89
89
|
|
|
@@ -296,7 +296,8 @@ const displayPlaybook = ({
|
|
|
296
296
|
if (wpSite.id === 1) {
|
|
297
297
|
siteRegex = /^wp_[a-z]+/i;
|
|
298
298
|
} else {
|
|
299
|
-
|
|
299
|
+
// eslint-disable-next-line security/detect-non-literal-regexp
|
|
300
|
+
siteRegex = new RegExp(`^wp_${parseInt(wpSite.id, 10)}_[a-z]+`, 'i');
|
|
300
301
|
}
|
|
301
302
|
const tableNamesInGroup = tableNames.filter(name => siteRegex.test(name));
|
|
302
303
|
return {
|
package/dist/bin/vip-sync.js
CHANGED
|
@@ -35,14 +35,14 @@ const appQuery = `id,name,environments{
|
|
|
35
35
|
await api.mutate({
|
|
36
36
|
// $FlowFixMe: gql template is not supported by flow
|
|
37
37
|
mutation: (0, _graphqlTag.default)`
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
}
|
|
38
|
+
mutation SyncEnvironmentMutation($input: AppEnvironmentSyncInput) {
|
|
39
|
+
syncEnvironment(input: $input) {
|
|
40
|
+
environment {
|
|
41
|
+
id
|
|
44
42
|
}
|
|
45
|
-
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
`,
|
|
46
46
|
variables: {
|
|
47
47
|
input: {
|
|
48
48
|
id: opts.app.id,
|
|
@@ -106,15 +106,29 @@ const appQuery = `id,name,environments{
|
|
|
106
106
|
// The rest of the iterations are just for moving the spinner
|
|
107
107
|
api.query({
|
|
108
108
|
// $FlowFixMe: gql template is not supported by flow
|
|
109
|
-
query: (0, _graphqlTag.default)`
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
109
|
+
query: (0, _graphqlTag.default)`
|
|
110
|
+
query App($id: Int, $sync: Int) {
|
|
111
|
+
app(id: $id) {
|
|
112
|
+
id
|
|
113
|
+
name
|
|
114
|
+
environments {
|
|
115
|
+
id
|
|
116
|
+
name
|
|
117
|
+
defaultDomain
|
|
118
|
+
branch
|
|
119
|
+
datacenter
|
|
120
|
+
syncProgress(sync: $sync) {
|
|
121
|
+
status
|
|
122
|
+
sync
|
|
123
|
+
steps {
|
|
124
|
+
name
|
|
125
|
+
status
|
|
126
|
+
}
|
|
114
127
|
}
|
|
115
128
|
}
|
|
116
129
|
}
|
|
117
|
-
}
|
|
130
|
+
}
|
|
131
|
+
`,
|
|
118
132
|
fetchPolicy: 'network-only',
|
|
119
133
|
variables: {
|
|
120
134
|
id: opts.app.id,
|
|
@@ -68,19 +68,20 @@ async function getBuildConfiguration(application, environment) {
|
|
|
68
68
|
// Disable the global GraphQL error handling, so we can catch Unauthorized errors and recommend next steps.
|
|
69
69
|
(0, _api.disableGlobalGraphQLErrorHandling)();
|
|
70
70
|
const buildConfigQuery = (0, _graphqlTag.default)`
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
71
|
+
query BuildConfig($appId: Int, $envId: Int) {
|
|
72
|
+
app(id: $appId) {
|
|
73
|
+
environments(id: $envId) {
|
|
74
|
+
id
|
|
75
|
+
buildConfiguration {
|
|
76
|
+
buildType
|
|
77
|
+
nodeBuildDockerEnv
|
|
78
|
+
nodeJSVersion
|
|
79
|
+
npmToken
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
`;
|
|
84
85
|
try {
|
|
85
86
|
const result = await api.query({
|
|
86
87
|
query: buildConfigQuery,
|
|
@@ -122,7 +123,7 @@ async function vipValidatePreflightCommand(arg, opt) {
|
|
|
122
123
|
};
|
|
123
124
|
await (0, _tracker.trackEvent)('validate_preflight_command_execute', baseTrackingParams);
|
|
124
125
|
logToConsole(' /\\ /\\__ _ _ __ _ __ ___ ___ _ __ (_) __ _ ');
|
|
125
|
-
logToConsole(
|
|
126
|
+
logToConsole(" / /_/ / _` | '__| '_ ` _ \\ / _ \\| '_ \\| |/ _` |");
|
|
126
127
|
logToConsole('/ __ / (_| | | | | | | | | (_) | | | | | (_| |');
|
|
127
128
|
logToConsole('\\/ /_/ \\__,_|_| |_| |_| |_|\\___/|_| |_|_|\\__,_|');
|
|
128
129
|
logToConsole('VIP Harmonia - Application testing made easy\n');
|
|
@@ -155,6 +156,7 @@ async function vipValidatePreflightCommand(arg, opt) {
|
|
|
155
156
|
const packageJSONfile = _path.default.resolve(opt.path, 'package.json');
|
|
156
157
|
let packageJSON;
|
|
157
158
|
try {
|
|
159
|
+
// eslint-disable-next-line security/detect-non-literal-require
|
|
158
160
|
packageJSON = require(packageJSONfile);
|
|
159
161
|
siteOptions.setPackageJSON(packageJSON);
|
|
160
162
|
} catch (error) {
|
package/dist/bin/vip-wp.js
CHANGED
|
@@ -100,15 +100,15 @@ const getTokenForCommand = async (appId, envId, command) => {
|
|
|
100
100
|
return api.mutate({
|
|
101
101
|
// $FlowFixMe: gql template is not supported by flow
|
|
102
102
|
mutation: (0, _graphqlTag.default)`
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
103
|
+
mutation TriggerWPCLICommandMutation($input: AppEnvironmentTriggerWPCLICommandInput) {
|
|
104
|
+
triggerWPCLICommandOnAppEnvironment(input: $input) {
|
|
105
|
+
inputToken
|
|
106
|
+
command {
|
|
107
|
+
guid
|
|
109
108
|
}
|
|
110
109
|
}
|
|
111
|
-
|
|
110
|
+
}
|
|
111
|
+
`,
|
|
112
112
|
variables: {
|
|
113
113
|
input: {
|
|
114
114
|
id: appId,
|
|
@@ -125,8 +125,8 @@ const cancelCommand = async guid => {
|
|
|
125
125
|
return api.mutate({
|
|
126
126
|
// $FlowFixMe: gql template is not supported by flow
|
|
127
127
|
mutation: (0, _graphqlTag.default)`
|
|
128
|
-
mutation cancelWPCLICommand($input: CancelWPCLICommandInput
|
|
129
|
-
cancelWPCLICommand(
|
|
128
|
+
mutation cancelWPCLICommand($input: CancelWPCLICommandInput) {
|
|
129
|
+
cancelWPCLICommand(input: $input) {
|
|
130
130
|
command {
|
|
131
131
|
id
|
|
132
132
|
}
|
|
@@ -34,6 +34,8 @@ const CREATE_DB_BACKUP_JOB_MUTATION = (0, _graphqlTag.default)`
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
`;
|
|
37
|
+
|
|
38
|
+
// TODO: Replace this with the codegen
|
|
37
39
|
exports.CREATE_DB_BACKUP_JOB_MUTATION = CREATE_DB_BACKUP_JOB_MUTATION;
|
|
38
40
|
const DB_BACKUP_JOB_STATUS_QUERY = (0, _graphqlTag.default)`
|
|
39
41
|
query AppBackupJobStatus($appId: Int!, $envId: Int!) {
|
|
@@ -104,12 +106,12 @@ class BackupDBCommand {
|
|
|
104
106
|
PREPARE: 'prepare',
|
|
105
107
|
GENERATE: 'generate'
|
|
106
108
|
};
|
|
107
|
-
constructor(app, env, trackerFn = () => {}) {
|
|
109
|
+
constructor(app, env, trackerFn = async () => {}) {
|
|
108
110
|
this.app = app;
|
|
109
111
|
this.env = env;
|
|
110
112
|
this.progressTracker = new _progress.ProgressTracker([{
|
|
111
113
|
id: this.steps.PREPARE,
|
|
112
|
-
name: 'Preparing'
|
|
114
|
+
name: 'Preparing for backup generation'
|
|
113
115
|
}, {
|
|
114
116
|
id: this.steps.GENERATE,
|
|
115
117
|
name: 'Generating backup'
|
|
@@ -117,11 +119,13 @@ class BackupDBCommand {
|
|
|
117
119
|
this.track = trackerFn;
|
|
118
120
|
}
|
|
119
121
|
log(msg) {
|
|
120
|
-
if (this.silent)
|
|
122
|
+
if (this.silent) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
121
125
|
console.log(msg);
|
|
122
126
|
}
|
|
123
127
|
isDone(job) {
|
|
124
|
-
return !job.inProgressLock;
|
|
128
|
+
return !(job !== null && job !== void 0 && job.inProgressLock);
|
|
125
129
|
}
|
|
126
130
|
|
|
127
131
|
/**
|
|
@@ -134,54 +138,53 @@ class BackupDBCommand {
|
|
|
134
138
|
this.progressTracker.stopPrinting();
|
|
135
139
|
}
|
|
136
140
|
async loadBackupJob() {
|
|
137
|
-
var _this$job, _this$job$metadata$
|
|
141
|
+
var _this$job$metadata$fi, _this$job$metadata$fi2, _this$job$progress;
|
|
138
142
|
this.job = await getBackupJob(this.app.id, this.env.id);
|
|
139
|
-
this.backupName = (
|
|
140
|
-
this.jobStatus = (_this$
|
|
141
|
-
if (
|
|
142
|
-
this.jobAge = (new Date() - new Date(this.job.completedAt)) / 1000 / 60;
|
|
143
|
+
this.backupName = (_this$job$metadata$fi = (_this$job$metadata$fi2 = this.job.metadata.find(meta => meta.name === 'backupName')) === null || _this$job$metadata$fi2 === void 0 ? void 0 : _this$job$metadata$fi2.value) !== null && _this$job$metadata$fi !== void 0 ? _this$job$metadata$fi : 'Unknown';
|
|
144
|
+
this.jobStatus = (_this$job$progress = this.job.progress) === null || _this$job$progress === void 0 ? void 0 : _this$job$progress.status;
|
|
145
|
+
if (this.job.completedAt) {
|
|
146
|
+
this.jobAge = (new Date().getTime() - new Date(this.job.completedAt).getTime()) / 1000 / 60;
|
|
143
147
|
} else {
|
|
144
148
|
this.jobAge = undefined;
|
|
145
149
|
}
|
|
146
150
|
return this.job;
|
|
147
151
|
}
|
|
148
152
|
async run(silent = false) {
|
|
149
|
-
var _this$
|
|
153
|
+
var _this$job;
|
|
150
154
|
this.silent = silent;
|
|
151
|
-
const readMoreMessage = '\nRead more about the limitations around database backups & exports here: https://docs.wpvip.com/technical-references/vip-dashboard/backups/ \n';
|
|
152
155
|
let noticeMessage = `\n${_chalk.default.yellow('NOTICE: ')}`;
|
|
153
|
-
noticeMessage += '
|
|
154
|
-
noticeMessage +=
|
|
156
|
+
noticeMessage += 'If a recent database backup does not exist, a new one will be generated for this environment. ';
|
|
157
|
+
noticeMessage += 'Learn more about this: https://docs.wpvip.com/technical-references/vip-dashboard/backups/#2-download-a-full-database-backup \n';
|
|
155
158
|
this.log(noticeMessage);
|
|
156
159
|
await this.loadBackupJob();
|
|
157
|
-
if ((_this$
|
|
160
|
+
if ((_this$job = this.job) !== null && _this$job !== void 0 && _this$job.inProgressLock) {
|
|
158
161
|
this.log('Database backup already in progress...');
|
|
159
162
|
} else {
|
|
160
163
|
try {
|
|
161
|
-
this.log('
|
|
164
|
+
this.log('Generating a new database backup...');
|
|
162
165
|
this.progressTracker.stepRunning(this.steps.PREPARE);
|
|
163
166
|
this.progressTracker.startPrinting();
|
|
164
167
|
await createBackupJob(this.app.id, this.env.id);
|
|
165
|
-
} catch (
|
|
166
|
-
|
|
168
|
+
} catch (stepErr) {
|
|
169
|
+
const err = stepErr;
|
|
167
170
|
this.progressTracker.stepFailed(this.steps.PREPARE);
|
|
168
171
|
this.stopProgressTracker();
|
|
169
|
-
if (
|
|
172
|
+
if (err.message.includes('Database backups limit reached')) {
|
|
170
173
|
await this.track('error', {
|
|
171
174
|
error_type: 'rate_limit_exceeded',
|
|
172
175
|
error_message: `Couldn't create a new database backup job: ${err === null || err === void 0 ? void 0 : err.message}`,
|
|
173
|
-
stack: err
|
|
176
|
+
stack: err.stack
|
|
174
177
|
});
|
|
175
|
-
let errMessage = err.message.replace('Database backups limit reached', '
|
|
176
|
-
errMessage = errMessage.replace('Retry after', '\
|
|
177
|
-
errMessage += `\
|
|
178
|
-
errMessage +=
|
|
178
|
+
let errMessage = err.message.replace('Database backups limit reached', 'A new database backup was not generated because a recently generated backup already exists.');
|
|
179
|
+
errMessage = errMessage.replace('Retry after', '\nIf you would like to run the same command, you can retry on or after:');
|
|
180
|
+
errMessage += `\nAlternatively, you can export the latest existing database backup by running: ${_chalk.default.green('vip @app.env export sql')}, right away.`;
|
|
181
|
+
errMessage += '\nLearn more about limitations around generating database backups: https://docs.wpvip.com/technical-references/vip-dashboard/backups/#0-limitations \n';
|
|
179
182
|
exit.withError(errMessage);
|
|
180
183
|
}
|
|
181
184
|
await this.track('error', {
|
|
182
185
|
error_type: 'db_backup_job_creation_failed',
|
|
183
186
|
error_message: `Database Backup job creation failed: ${err === null || err === void 0 ? void 0 : err.message}`,
|
|
184
|
-
stack: err
|
|
187
|
+
stack: err.stack
|
|
185
188
|
});
|
|
186
189
|
exit.withError(`Couldn't create a new database backup job: ${err === null || err === void 0 ? void 0 : err.message}`);
|
|
187
190
|
}
|
|
@@ -190,7 +193,8 @@ class BackupDBCommand {
|
|
|
190
193
|
this.progressTracker.stepRunning(this.steps.GENERATE);
|
|
191
194
|
try {
|
|
192
195
|
await (0, _utils.pollUntil)(this.loadBackupJob.bind(this), DB_BACKUP_PROGRESS_POLL_INTERVAL, this.isDone.bind(this));
|
|
193
|
-
} catch (
|
|
196
|
+
} catch (e) {
|
|
197
|
+
const err = e;
|
|
194
198
|
this.progressTracker.stepFailed(this.steps.GENERATE);
|
|
195
199
|
this.stopProgressTracker();
|
|
196
200
|
await this.track('error', {
|
|
@@ -206,7 +210,7 @@ class BackupDBCommand {
|
|
|
206
210
|
if (this.jobStatus !== 'success') {
|
|
207
211
|
exit.withError('Failed to create a new database backup');
|
|
208
212
|
} else {
|
|
209
|
-
this.log(
|
|
213
|
+
this.log('New database backup created');
|
|
210
214
|
}
|
|
211
215
|
}
|
|
212
216
|
}
|
|
@@ -32,7 +32,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
32
32
|
|
|
33
33
|
const EXPORT_SQL_PROGRESS_POLL_INTERVAL = 1000;
|
|
34
34
|
const BACKUP_AND_JOB_STATUS_QUERY = (0, _graphqlTag.default)`
|
|
35
|
-
query AppBackupAndJobStatus(
|
|
35
|
+
query AppBackupAndJobStatus($appId: Int!, $envId: Int!) {
|
|
36
36
|
app(id: $appId) {
|
|
37
37
|
id
|
|
38
38
|
environments(id: $envId) {
|
|
@@ -186,7 +186,6 @@ async function createExportJob(appId, envId, backupId) {
|
|
|
186
186
|
*/
|
|
187
187
|
class ExportSQLCommand {
|
|
188
188
|
steps = {
|
|
189
|
-
GENERATE: 'generate',
|
|
190
189
|
PREPARE: 'prepare',
|
|
191
190
|
CREATE: 'create',
|
|
192
191
|
DOWNLOAD_LINK: 'downloadLink',
|
|
@@ -207,7 +206,7 @@ class ExportSQLCommand {
|
|
|
207
206
|
this.generateBackup = options.generateBackup || false;
|
|
208
207
|
this.progressTracker = new _progress.ProgressTracker([{
|
|
209
208
|
id: this.steps.PREPARE,
|
|
210
|
-
name: 'Preparing'
|
|
209
|
+
name: 'Preparing for backup download'
|
|
211
210
|
}, {
|
|
212
211
|
id: this.steps.CREATE,
|
|
213
212
|
name: 'Creating backup copy'
|
|
@@ -19,16 +19,8 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
const mutation = (0, _graphqlTag.default)`
|
|
22
|
-
mutation PurgePageCacheMutation(
|
|
23
|
-
$appId:
|
|
24
|
-
$envId: Int!
|
|
25
|
-
$urls: [String!]!
|
|
26
|
-
) {
|
|
27
|
-
purgePageCache( input: {
|
|
28
|
-
appId: $appId
|
|
29
|
-
environmentId: $envId
|
|
30
|
-
urls: $urls
|
|
31
|
-
} ) {
|
|
22
|
+
mutation PurgePageCacheMutation($appId: Int!, $envId: Int!, $urls: [String!]!) {
|
|
23
|
+
purgePageCache(input: { appId: $appId, environmentId: $envId, urls: $urls }) {
|
|
32
24
|
success
|
|
33
25
|
urls
|
|
34
26
|
}
|
|
@@ -21,11 +21,17 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
21
21
|
const LIMIT_MAX = 5000;
|
|
22
22
|
exports.LIMIT_MAX = LIMIT_MAX;
|
|
23
23
|
const QUERY_ENVIRONMENT_LOGS = (0, _graphqlTag.default)`
|
|
24
|
-
query GetAppLogs(
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
query GetAppLogs(
|
|
25
|
+
$appId: Int
|
|
26
|
+
$envId: Int
|
|
27
|
+
$type: AppEnvironmentLogType
|
|
28
|
+
$limit: Int
|
|
29
|
+
$after: String
|
|
30
|
+
) {
|
|
31
|
+
app(id: $appId) {
|
|
32
|
+
environments(id: $envId) {
|
|
27
33
|
id
|
|
28
|
-
logs(
|
|
34
|
+
logs(type: $type, limit: $limit, after: $after) {
|
|
29
35
|
nodes {
|
|
30
36
|
timestamp
|
|
31
37
|
message
|
package/dist/lib/cli/format.js
CHANGED