@automattic/vip 2.32.4 → 2.33.0-dev1

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/CONTRIBUTING.md CHANGED
@@ -72,19 +72,39 @@ For help, see: https://nodejs.org/en/docs/inspector
72
72
 
73
73
  New libraries should generally support both CLI and web contexts, though some cases that won't make sense (e.g. formatting for CLI output). Ensuring the libraries are useful everywhere will allow us to offer consistent experiences regardless of the interface.
74
74
 
75
+ ### go-search-replace binaries
76
+
77
+ Some unit tests require some go-search-replace executable binary files to run. Binaries files for
78
+ several OS architectures can be downloaded
79
+ from https://github.com/Automattic/go-search-replace/releases/
80
+
81
+ If, for some reason, you need to compile these binaries yourself, please follow instructions
82
+ at https://github.com/Automattic/go-search-replace
83
+
84
+ ### Generating the types
85
+
86
+ If you're an employee of Automattic, you can follow these steps to regenerate the GraphQL types
87
+ used.
88
+
89
+ 1. Get a hold of `schema.gql` and paste it in project root - this is the schema of the endpoint that
90
+ we communicate with.
91
+ 2. Run `npm run typescript:codegen:install-dependencies` - this will install the codegen
92
+ dependencies without updating `package.json`
93
+ 3. Run `npm run typescript:codegen:generate` - this will regenerate the types
94
+
75
95
  ## Release & Deployment Process
76
96
 
77
97
  Our release flow for VIP CLI follows this pattern:
78
98
 
79
- **_feature branch -> develop branch -> trunk branch -> NPM release_**
99
+ **_feature branch -> trunk branch -> NPM release_**
80
100
 
81
101
  - For feature branches, please follow A8C branch naming conventions (e.g.- `add/data-sync-command`, `fix/subsite-launch-command`, etc.)
82
102
  - Include a Changelog for all npm version releases, including any minor or major versions
83
103
  - This is a public repository. Please do not include any internal links in PRs, changelogs, testing instructions, etc.
84
- - Merge changes from your feature branch to the `develop` branch
85
- - If you are ready to release your changes publicly, merge your changes from the `develop` branch to the `trunk` branch. All changes that are not ready to be public should be feature flagged or stay in the `develop` branch to avoid conflicts when releasing urgent fixes (not recommended).
104
+ - Merge changes from your feature branch to the `trunk` branch when they are ready to be published publicly.
86
105
  - 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.
87
106
 
107
+ If you need to publish a security release, see [details below](#patching-old-releases).
88
108
  ### Changelogs
89
109
 
90
110
  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`.
@@ -97,6 +117,12 @@ We use a custom pre-publish [script](https://github.com/Automattic/vip/blob/trun
97
117
 
98
118
  Further checks can be added to this flow as needed.
99
119
 
120
+ ### Versioning Guidelines
121
+
122
+ - `patch`: for non-breaking changes/bugfixes and small updates.
123
+ - `minor`: for some new features, bug fixes, and other non-breaking changes.
124
+ - `major`: for breaking changes.
125
+
100
126
  ### New Releases
101
127
 
102
128
  Prepare the release by making sure that:
@@ -108,6 +134,8 @@ Prepare the release by making sure that:
108
134
  1. Make sure not to merge anymore changes into `develop` while all the release steps below are in
109
135
  progress.
110
136
 
137
+ You can release either using GitHub Actions or locally.
138
+
111
139
  #### Changelog Generator Hint:
112
140
 
113
141
  In the first step, you'll need to generate a changelog.
@@ -119,14 +147,32 @@ export LAST_RELEASE_DATE=2021-08-25T13:40:00+02
119
147
  gh pr list --search "is:merged sort:updated-desc closed:>$LAST_RELEASE_DATE" | sed -e 's/\s\+\S\+\tMERGED.*$//' -e 's/^/- #/'
120
148
  ```
121
149
 
122
- Then, let's publish:
123
150
 
124
- 1. Create a pull request that adds the next version's changelog into `develop`. Use the Changelog
151
+ #### Publishing via GitHub Actions (preferred)
152
+
153
+ 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.
154
+
155
+ 1. Initiate the [release process here](https://github.com/Automattic/vip-cli/actions/workflows/npm-prepare-release.yml).
156
+ 1. On the right-hand side, select "Run Workflow".
157
+ 1. Pick your preferred version bump.
158
+ 1. Click `Run Workflow`.
159
+ 1. Wait for a pull request to appear. The pull request will update the version number and shall be assigned to you.
160
+ 1. When ready, merge the pull request. This will lead to a new version to be [published on npmjs.com](https://www.npmjs.com/package/@automattic/vip).
161
+ 1. Another pull request will be created to bump to a development version, also assigned to you. Merge it to finish the process.
162
+
163
+ #### Note on NPM token
164
+
165
+ Publishing via the GitHub Action requires that the `NPM_TOKEN` be set correctly in GitHub Actions secrets. This should be an npm token generated for a bot user on [the npm @automattic org](https://www.npmjs.com/settings/automattic) that has publish access to this repo.
166
+
167
+ #### Publishing locally
168
+
169
+ To publish locally, follow these steps:
170
+
171
+ 1. Create a pull request that adds the next version's changelog into `trunk`. Use the Changelog
125
172
  Generate Hint above to generate the changelog, and refer to previous releases to ensure that your
126
- format matches.
127
- 1. Create a pull request that merges `develop` to `trunk`.
173
+ format matches.
128
174
  1. Merge it after approval.
129
- 1. Make sure trunk branch is up-to-date `git pull`.
175
+ 1. Make sure `trunk` branch is up-to-date `git pull`.
130
176
  1. Make sure to clean all of your repositories of extra files. Run a dangerous, destructive
131
177
  command `git clean -xfd` to do so.
132
178
  1. Run `npm install`.
@@ -168,23 +214,3 @@ For these cases:
168
214
  1. Follow the release steps outlined above (as a `patch` release).
169
215
 
170
216
  Then, repeat for any additional versions that we need to patch.
171
-
172
- ### go-search-replace binaries
173
-
174
- Some unit tests require some go-search-replace executable binary files to run. Binaries files for
175
- several OS architectures can be downloaded
176
- from https://github.com/Automattic/go-search-replace/releases/
177
-
178
- If, for some reason, you need to compile these binaries yourself, please follow instructions
179
- at https://github.com/Automattic/go-search-replace
180
-
181
- ### Generating the types
182
-
183
- If you're an employee of Automattic, you can follow these steps to regenerate the GraphQL types
184
- used.
185
-
186
- 1. Get a hold of `schema.gql` and paste it in project root - this is the schema of the endpoint that
187
- we communicate with.
188
- 2. Run `npm run typescript:codegen:install-dependencies` - this will install the codegen
189
- dependencies without updating `package.json`
190
- 3. Run `npm run typescript:codegen:generate` - this will regenerate the types
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ *
5
+ * @format
6
+ */
7
+
8
+ /**
9
+ * External dependencies
10
+ */
11
+
12
+ /**
13
+ * Internal dependencies
14
+ */
15
+ "use strict";
16
+
17
+ var _command = _interopRequireDefault(require("../lib/cli/command"));
18
+ var _tracker = require("../lib/tracker");
19
+ var _backupDb = require("../commands/backup-db");
20
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21
+ const examples = [{
22
+ usage: 'vip backup db @mysite.develop',
23
+ description: 'Trigger a new backup for your database of the @mysite.develop environment'
24
+ }];
25
+ const appQuery = `
26
+ id,
27
+ name,
28
+ type,
29
+ organization { id, name },
30
+ environments{
31
+ id
32
+ appId
33
+ type
34
+ name
35
+ primaryDomain { name }
36
+ uniqueLabel
37
+ }
38
+ `;
39
+ void (0, _command.default)({
40
+ appContext: true,
41
+ appQuery,
42
+ envContext: true,
43
+ module: 'backup-db',
44
+ requiredArgs: 0,
45
+ usage: 'vip backup db'
46
+ }).examples(examples).argv(process.argv, async (arg, {
47
+ app,
48
+ env
49
+ }) => {
50
+ const trackerFn = (0, _tracker.makeCommandTracker)('backup_db', {
51
+ app: app.id,
52
+ env: env.uniqueLabel
53
+ });
54
+ await trackerFn('execute');
55
+ const cmd = new _backupDb.BackupDBCommand(app, env, trackerFn);
56
+ await cmd.run();
57
+ await trackerFn('success');
58
+ });
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * External dependencies
5
+ */
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ "use strict";
11
+
12
+ var _command = _interopRequireDefault(require("../lib/cli/command"));
13
+ var _tracker = require("../lib/tracker");
14
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
+ void (0, _command.default)({
16
+ usage: 'vip backup'
17
+ }).command('db', 'Trigger a new backup for your database').example('vip backup sql @mysite.develop', 'Trigger a new backup for your database of the @mysite.develop environment').argv(process.argv, async () => {
18
+ await (0, _tracker.trackEvent)('vip_backup_command_execute');
19
+ });
@@ -34,6 +34,7 @@ const appQuery = `
34
34
  id
35
35
  appId
36
36
  type
37
+ name
37
38
  primaryDomain {
38
39
  id
39
40
  name
@@ -30,6 +30,7 @@ const appQuery = `
30
30
  id
31
31
  appId
32
32
  type
33
+ name
33
34
  primaryDomain {
34
35
  id
35
36
  name
@@ -30,6 +30,7 @@ environments{
30
30
  id
31
31
  appId
32
32
  type
33
+ name
33
34
  isK8sResident
34
35
  primaryDomain {
35
36
  id
package/dist/bin/vip.js CHANGED
@@ -28,7 +28,7 @@ if (_config.default && _config.default.environment !== 'production') {
28
28
  const tokenURL = 'https://dashboard.wpvip.com/me/cli/token';
29
29
  const runCmd = async function () {
30
30
  const cmd = (0, _command.default)();
31
- cmd.command('logout', 'Logout from your current session').command('app', 'List and modify your 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');
31
+ 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');
32
32
  cmd.argv(process.argv);
33
33
  };
34
34
  function doesArgvHaveAtLeastOneParam(argv, params) {
@@ -10,6 +10,7 @@ var _api = _interopRequireWildcard(require("../lib/api"));
10
10
  var exit = _interopRequireWildcard(require("../lib/cli/exit"));
11
11
  var _utils = require("../lib/utils");
12
12
  var _progress = require("../lib/cli/progress");
13
+ var _format = require("../lib/cli/format");
13
14
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
14
15
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
15
16
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -148,10 +149,6 @@ class BackupDBCommand {
148
149
  async run(silent = false) {
149
150
  var _this$job4;
150
151
  this.silent = silent;
151
- let noticeMessage = `\n${_chalk.default.yellow('NOTICE: ')}`;
152
- noticeMessage += 'If a recent database backup does not exist, a new one will be generated for this environment. ';
153
- noticeMessage += 'Learn more about this: https://docs.wpvip.com/technical-references/vip-dashboard/backups/#2-download-a-full-database-backup \n';
154
- this.log(noticeMessage);
155
152
  await this.loadBackupJob();
156
153
  if ((_this$job4 = this.job) !== null && _this$job4 !== void 0 && _this$job4.inProgressLock) {
157
154
  this.log('Database backup already in progress...');
@@ -175,7 +172,7 @@ class BackupDBCommand {
175
172
  stack: error.stack
176
173
  });
177
174
  const errMessage = `A new database backup was not generated because a recently generated backup already exists.
178
- If you would like to run the same command, you can retry on or after: ${retryAfter}
175
+ If you would like to run the same command, you can retry on or after ${(0, _format.formatDuration)(new Date(), new Date(retryAfter))}
179
176
  Alternatively, you can export the latest existing database backup by running: ${_chalk.default.green('vip @app.env export sql')}, right away.
180
177
  Learn more about limitations around generating database backups: https://docs.wpvip.com/technical-references/vip-dashboard/backups/#0-limitations
181
178
  `;
@@ -8,6 +8,7 @@ var _graphqlTag = _interopRequireDefault(require("graphql-tag"));
8
8
  var _fs = _interopRequireDefault(require("fs"));
9
9
  var _https = _interopRequireDefault(require("https"));
10
10
  var _path = _interopRequireDefault(require("path"));
11
+ var _chalk = _interopRequireDefault(require("chalk"));
11
12
  var _api = _interopRequireWildcard(require("../lib/api"));
12
13
  var _format = require("../lib/cli/format");
13
14
  var _progress = require("../lib/cli/progress");
@@ -313,6 +314,10 @@ class ExportSQLCommand {
313
314
  }
314
315
  async runBackupJob() {
315
316
  const cmd = new _backupDb.BackupDBCommand(this.app, this.env);
317
+ let noticeMessage = `\n${_chalk.default.yellow('NOTICE: ')}`;
318
+ noticeMessage += 'If a recent database backup does not exist, a new one will be generated for this environment. ';
319
+ noticeMessage += 'Learn more about this: https://docs.wpvip.com/technical-references/vip-dashboard/backups/#2-download-a-full-database-backup \n';
320
+ this.log(noticeMessage);
316
321
  await cmd.run(false);
317
322
  }
318
323
 
@@ -7,6 +7,7 @@ exports.RunningSprite = exports.RUNNING_SPRITE_GLYPHS = void 0;
7
7
  exports.capitalize = capitalize;
8
8
  exports.formatBytes = void 0;
9
9
  exports.formatData = formatData;
10
+ exports.formatDuration = formatDuration;
10
11
  exports.formatEnvironment = formatEnvironment;
11
12
  exports.formatSearchReplaceValues = formatSearchReplaceValues;
12
13
  exports.getGlyphForStatus = getGlyphForStatus;
@@ -195,4 +196,33 @@ const formatBytes = (bytes, decimals = 2) => {
195
196
  const idx = Math.floor(Math.log(bytes) / Math.log(bytesMultiplier));
196
197
  return `${parseFloat((bytes / Math.pow(bytesMultiplier, idx)).toFixed(dm))} ${sizes[idx]}`;
197
198
  };
198
- exports.formatBytes = formatBytes;
199
+
200
+ /**
201
+ * Get the duration between two dates
202
+ *
203
+ * @param {Date} from The start date
204
+ * @param {Date} to The end date
205
+ * @returns {string} The duration between the two dates
206
+ */
207
+ exports.formatBytes = formatBytes;
208
+ function formatDuration(from, to) {
209
+ const millisecondsPerSecond = 1000;
210
+ const millisecondsPerMinute = 60 * millisecondsPerSecond;
211
+ const millisecondsPerHour = 60 * millisecondsPerMinute;
212
+ const millisecondsPerDay = 24 * millisecondsPerHour;
213
+ const duration = Math.abs(from.getTime() - to.getTime());
214
+ const days = Math.floor(duration / millisecondsPerDay);
215
+ const hours = Math.floor(duration % millisecondsPerDay / millisecondsPerHour);
216
+ const minutes = Math.floor(duration % millisecondsPerHour / millisecondsPerMinute);
217
+ let durationString = '';
218
+ if (days > 0) {
219
+ durationString += `${days} day${days > 1 ? 's' : ''} `;
220
+ }
221
+ if (hours > 0) {
222
+ durationString += `${hours} hour${hours > 1 ? 's' : ''} `;
223
+ }
224
+ if (minutes > 0) {
225
+ durationString += `${minutes} minute${minutes > 1 ? 's' : ''} `;
226
+ }
227
+ return durationString.trim();
228
+ }
@@ -398,7 +398,7 @@ async function checkEnvHealth(lando, instancePath) {
398
398
  urls[url] = service.service;
399
399
  });
400
400
  });
401
- const urlsToScan = Object.keys(urls);
401
+ const urlsToScan = Object.keys(urls).filter(url => !url.includes('*'));
402
402
  let scanResults = [];
403
403
  if (Array.isArray(app.urls)) {
404
404
  scanResults = app.urls;