@automattic/vip 4.0.13 → 4.1.1
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/dist/commands/export-sql.js +19 -9
- package/dist/lib/utils.js +34 -4
- package/docs/RELEASING.md +9 -3
- package/helpers/sync-shrinkwrap.js +32 -0
- package/npm-shrinkwrap.json +15500 -0
- package/package.json +5 -2
|
@@ -16,10 +16,14 @@ var _downloadFile = require("../lib/http/download-file");
|
|
|
16
16
|
var _liveBackupCopy = _interopRequireWildcard(require("../lib/live-backup-copy"));
|
|
17
17
|
var liveBackupCopy = _liveBackupCopy;
|
|
18
18
|
var _retry = require("../lib/retry");
|
|
19
|
+
var _userError = _interopRequireDefault(require("../lib/user-error"));
|
|
19
20
|
var _utils = require("../lib/utils");
|
|
20
21
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
21
22
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
22
23
|
const EXPORT_SQL_PROGRESS_POLL_INTERVAL = 1000;
|
|
24
|
+
|
|
25
|
+
// Maximum allowed size for a live backup copy configuration file (500 KB).
|
|
26
|
+
const MAX_LIVE_BACKUP_CONFIG_SIZE_BYTES = 500 * 1024;
|
|
23
27
|
const BACKUP_AND_JOB_STATUS_QUERY = (0, _graphqlTag.default)`
|
|
24
28
|
query AppBackupAndJobStatus($appId: Int!, $envId: Int!) {
|
|
25
29
|
app(id: $appId) {
|
|
@@ -455,10 +459,10 @@ class ExportSQLCommand {
|
|
|
455
459
|
}
|
|
456
460
|
async generateLiveBackupCopy() {
|
|
457
461
|
if (!this.liveBackupCopyCLIOptions) {
|
|
458
|
-
throw new
|
|
462
|
+
throw new _userError.default('Configuration file is required for live backup copy.');
|
|
459
463
|
}
|
|
460
464
|
if (!this.app.id || !this.env.id) {
|
|
461
|
-
throw new
|
|
465
|
+
throw new _userError.default('App ID and Environment ID are required to start live backup copy.');
|
|
462
466
|
}
|
|
463
467
|
const config = this.getLiveBackupConfigFromCLIOptions();
|
|
464
468
|
try {
|
|
@@ -478,7 +482,7 @@ class ExportSQLCommand {
|
|
|
478
482
|
this.progressTracker.stepSuccess(this.steps.DOWNLOAD_LINK, [this.generateDownloadURLOutputString(result.url)]);
|
|
479
483
|
return result;
|
|
480
484
|
} catch (err) {
|
|
481
|
-
const message =
|
|
485
|
+
const message = (0, _utils.parseApiError)(err) ?? 'Unknown error';
|
|
482
486
|
await this.track('error', {
|
|
483
487
|
error_type: 'live_backup_copy',
|
|
484
488
|
error_message: message,
|
|
@@ -512,17 +516,23 @@ class ExportSQLCommand {
|
|
|
512
516
|
};
|
|
513
517
|
}
|
|
514
518
|
loadLiveBackupCopyConfig(configFile) {
|
|
515
|
-
if (!_fs.default.existsSync(configFile)) {
|
|
516
|
-
throw new Error(`Configuration file not found: ${configFile}`);
|
|
517
|
-
}
|
|
518
519
|
try {
|
|
519
|
-
|
|
520
|
+
// Read the file once to avoid a check-then-use race condition.
|
|
521
|
+
const fileContents = _fs.default.readFileSync(configFile, 'utf-8');
|
|
522
|
+
const size = Buffer.byteLength(fileContents);
|
|
523
|
+
if (size > MAX_LIVE_BACKUP_CONFIG_SIZE_BYTES) {
|
|
524
|
+
throw new _userError.default(`Configuration file is too large (${(0, _format.formatBytes)(size)}); the maximum allowed size is ${(0, _format.formatBytes)(MAX_LIVE_BACKUP_CONFIG_SIZE_BYTES)}. For large or complex exports, use the \`--wpcli-command\` option instead.`);
|
|
525
|
+
}
|
|
526
|
+
return JSON.parse(fileContents);
|
|
520
527
|
} catch (err) {
|
|
528
|
+
if (err instanceof _userError.default) {
|
|
529
|
+
throw err;
|
|
530
|
+
}
|
|
521
531
|
const errMessage = err instanceof Error ? err.message : 'Unknown error';
|
|
522
532
|
if (err instanceof SyntaxError) {
|
|
523
|
-
throw new
|
|
533
|
+
throw new _userError.default(`Invalid JSON in configuration file: ${configFile} - ${errMessage}`);
|
|
524
534
|
}
|
|
525
|
-
throw new
|
|
535
|
+
throw new _userError.default(`Error reading configuration file: ${configFile} - ${errMessage}`);
|
|
526
536
|
}
|
|
527
537
|
}
|
|
528
538
|
}
|
package/dist/lib/utils.js
CHANGED
|
@@ -79,19 +79,49 @@ function getAbsolutePath(filePath) {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
|
-
*
|
|
82
|
+
* Extract a message from a raw HTTP response body (Apollo's `ServerError.bodyText`).
|
|
83
83
|
*
|
|
84
|
-
*
|
|
84
|
+
* The body may be either `{"status":"error","message":"..."}` (e.g. a 413 whose
|
|
85
|
+
* top-level message is only `Received status code 413`) or a GraphQL
|
|
86
|
+
* `{"errors":[{"message":"..."}]}` payload.
|
|
87
|
+
*/
|
|
88
|
+
function parseJSONBodyErrorMessage(bodyText) {
|
|
89
|
+
try {
|
|
90
|
+
const body = JSON.parse(bodyText);
|
|
91
|
+
if (body?.errors?.[0]?.message) {
|
|
92
|
+
return body.errors[0].message;
|
|
93
|
+
}
|
|
94
|
+
if (body?.message) {
|
|
95
|
+
return body.message;
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
// Body wasn't JSON; nothing to extract.
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Parse error object and return probable error.
|
|
85
104
|
*
|
|
86
|
-
*
|
|
105
|
+
* Accepts either a known API error shape or an `unknown` value (e.g. a caught
|
|
106
|
+
* error), so callers do not need to cast before passing it in.
|
|
87
107
|
*/
|
|
88
|
-
function parseApiError(
|
|
108
|
+
function parseApiError(error) {
|
|
109
|
+
const err = error;
|
|
89
110
|
if (err?.networkError?.message) {
|
|
90
111
|
return err?.networkError?.message;
|
|
91
112
|
}
|
|
92
113
|
if (err?.graphQLErrors?.[0]?.message) {
|
|
93
114
|
return err.graphQLErrors[0].message;
|
|
94
115
|
}
|
|
116
|
+
|
|
117
|
+
// Apollo's `ServerError` exposes the raw HTTP response body as `bodyText`,
|
|
118
|
+
// which often holds a more specific message than the generic top-level one.
|
|
119
|
+
if (typeof err?.bodyText === 'string') {
|
|
120
|
+
const bodyTextMessage = parseJSONBodyErrorMessage(err.bodyText);
|
|
121
|
+
if (bodyTextMessage) {
|
|
122
|
+
return bodyTextMessage;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
95
125
|
if (err?.message) {
|
|
96
126
|
return err?.message;
|
|
97
127
|
}
|
package/docs/RELEASING.md
CHANGED
|
@@ -76,6 +76,12 @@ You can release either using GitHub Actions or locally.
|
|
|
76
76
|
|
|
77
77
|
This is the preferred method for pushing out the latest release. The workflow runs a bunch of validations, generates a build, bump versions + tags, pushes out to npm, and bumps to the next dev version.
|
|
78
78
|
|
|
79
|
+
The repository uses `package-lock.json` for npm 12 development and CI installs. An identical
|
|
80
|
+
`npm-shrinkwrap.json` is published with npm 11 so npm 11 and older consumers retain a locked CLI
|
|
81
|
+
dependency tree. Run `npm run sync:shrinkwrap` after changing `package-lock.json`; CI rejects drift
|
|
82
|
+
between the two files. The publish workflows intentionally use npm 11 because npm 12 excludes
|
|
83
|
+
`npm-shrinkwrap.json` from package tarballs.
|
|
84
|
+
|
|
79
85
|
Please keep in mind internal guidelines before releasing.
|
|
80
86
|
|
|
81
87
|
To release, follow these steps:
|
|
@@ -119,7 +125,7 @@ To publish locally, follow these steps:
|
|
|
119
125
|
1. Push the tag to GitHub (`git push --tags`)
|
|
120
126
|
1. Push the trunk branch `git push`
|
|
121
127
|
1. Make sure you're part of the Automattic organization in npm
|
|
122
|
-
1.
|
|
128
|
+
1. Use npm 11 and publish the release (`npx --yes --package=npm@11 npm publish --access public`). The script will do some extra checks (
|
|
123
129
|
node version, branch, etc) to ensure everything is correct. If all looks good, the new version
|
|
124
130
|
will be published and you can proceed.
|
|
125
131
|
1. Edit [the release on GitHub](https://github.com/Automattic/vip-cli/releases) to include a description
|
|
@@ -137,8 +143,8 @@ In order to do that, please follow this:
|
|
|
137
143
|
|
|
138
144
|
<summary><details>
|
|
139
145
|
|
|
140
|
-
1.
|
|
141
|
-
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
|
+
1. Set the dev version with npm 11 so both lockfiles remain synchronized. Example: `npx --yes --package=npm@11 npm version --no-git-tag-version 1.4.0-dev1`.
|
|
147
|
+
1. Run `npx --yes --package=npm@11 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`).
|
|
142
148
|
|
|
143
149
|
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.
|
|
144
150
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const { copyFileSync, readFileSync } = require( 'node:fs' );
|
|
2
|
+
const path = require( 'node:path' );
|
|
3
|
+
|
|
4
|
+
const PACKAGE_LOCK = 'package-lock.json';
|
|
5
|
+
const NPM_SHRINKWRAP = 'npm-shrinkwrap.json';
|
|
6
|
+
|
|
7
|
+
function syncShrinkwrap( { cwd = process.cwd(), check = false } = {} ) {
|
|
8
|
+
const packageLockPath = path.join( cwd, PACKAGE_LOCK );
|
|
9
|
+
const shrinkwrapPath = path.join( cwd, NPM_SHRINKWRAP );
|
|
10
|
+
|
|
11
|
+
if ( check ) {
|
|
12
|
+
const packageLock = readFileSync( packageLockPath );
|
|
13
|
+
const shrinkwrap = readFileSync( shrinkwrapPath );
|
|
14
|
+
if ( ! packageLock.equals( shrinkwrap ) ) {
|
|
15
|
+
throw new Error( `${ NPM_SHRINKWRAP } is out of sync with ${ PACKAGE_LOCK }` );
|
|
16
|
+
}
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
copyFileSync( packageLockPath, shrinkwrapPath );
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if ( require.main === module ) {
|
|
24
|
+
try {
|
|
25
|
+
syncShrinkwrap( { check: process.argv.includes( '--check' ) } );
|
|
26
|
+
} catch ( error ) {
|
|
27
|
+
console.error( error.message );
|
|
28
|
+
process.exitCode = 1;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = { syncShrinkwrap };
|