@hubspot/cli 4.1.7 → 4.1.8-beta.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.
@@ -7,12 +7,8 @@ const {
7
7
  } = require('../../lib/commonOpts');
8
8
  const { trackCommandUsage } = require('../../lib/usageTracking');
9
9
  const { logger } = require('@hubspot/cli-lib/logger');
10
- const Spinnies = require('spinnies');
11
- const { initiateSync } = require('@hubspot/cli-lib/sandboxes');
12
10
  const { loadAndValidateOptions } = require('../../lib/validation');
13
11
  const { i18n } = require('@hubspot/cli-lib/lib/lang');
14
- const { logErrorInstance } = require('@hubspot/cli-lib/errorHandlers');
15
- const { ENVIRONMENTS } = require('@hubspot/cli-lib/lib/constants');
16
12
  const { EXIT_CODES } = require('../../lib/enums/exitCodes');
17
13
  const { getAccountConfig, getEnv } = require('@hubspot/cli-lib');
18
14
  const { getHubSpotWebsiteOrigin } = require('@hubspot/cli-lib/lib/urls');
@@ -20,13 +16,12 @@ const { promptUser } = require('../../lib/prompts/promptUtils');
20
16
  const { uiLine } = require('../../lib/ui');
21
17
  const {
22
18
  getAccountName,
23
- getAvailableSyncTypes,
24
- pollSyncTaskStatus,
19
+ sandboxTypeMap,
20
+ DEVELOPER_SANDBOX,
21
+ STANDARD_SANDBOX,
25
22
  } = require('../../lib/sandboxes');
26
- const {
27
- isMissingScopeError,
28
- isSpecifiedError,
29
- } = require('@hubspot/cli-lib/errorHandlers/apiErrors');
23
+ const { syncSandbox } = require('../../lib/sandbox-sync');
24
+ const { getValidEnv } = require('@hubspot/cli-lib/lib/environment');
30
25
 
31
26
  const i18nKey = 'cli.commands.sandbox.subcommands.sync';
32
27
 
@@ -39,9 +34,7 @@ exports.handler = async options => {
39
34
  const { force } = options; // For scripting purposes
40
35
  const accountId = getAccountId(options);
41
36
  const accountConfig = getAccountConfig(accountId);
42
- const spinnies = new Spinnies({
43
- succeedColor: 'white',
44
- });
37
+ const env = getValidEnv(getEnv(accountId));
45
38
 
46
39
  trackCommandUsage('sandbox-sync', null, accountId);
47
40
 
@@ -51,10 +44,8 @@ exports.handler = async options => {
51
44
  accountConfig.sandboxAccountType === undefined ||
52
45
  accountConfig.sandboxAccountType === null
53
46
  ) {
54
- trackCommandUsage('sandbox-sync', { successful: false }, accountId);
55
-
56
47
  logger.error(i18n(`${i18nKey}.failure.notSandbox`));
57
-
48
+ trackCommandUsage('sandbox-sync', { successful: false }, accountId);
58
49
  process.exit(EXIT_CODES.ERROR);
59
50
  }
60
51
 
@@ -67,12 +58,15 @@ exports.handler = async options => {
67
58
  sandboxName: getAccountName(accountConfig),
68
59
  })
69
60
  );
61
+ trackCommandUsage('sandbox-sync', { successful: false }, accountId);
70
62
  process.exit(EXIT_CODES.ERROR);
71
63
  }
72
64
 
73
65
  const parentAccountConfig = getAccountConfig(parentAccountId);
74
- const isDevelopmentSandbox = accountConfig.sandboxAccountType === 'DEVELOPER';
75
- const isStandardSandbox = accountConfig.sandboxAccountType === 'STANDARD';
66
+ const isDevelopmentSandbox =
67
+ sandboxTypeMap[accountConfig.sandboxAccountType] === DEVELOPER_SANDBOX;
68
+ const isStandardSandbox =
69
+ sandboxTypeMap[accountConfig.sandboxAccountType] === STANDARD_SANDBOX;
76
70
 
77
71
  if (isDevelopmentSandbox) {
78
72
  logger.log(i18n(`${i18nKey}.info.developmentSandbox`));
@@ -100,12 +94,13 @@ exports.handler = async options => {
100
94
  },
101
95
  ]);
102
96
  if (!confirmed) {
97
+ trackCommandUsage('sandbox-sync', { successful: false }, accountId);
103
98
  process.exit(EXIT_CODES.SUCCESS);
104
99
  }
105
100
  }
106
101
  } else if (isStandardSandbox) {
107
102
  const standardSyncUrl = `${getHubSpotWebsiteOrigin(
108
- getEnv(accountId) === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD
103
+ env
109
104
  )}/sandboxes-developer/${parentAccountId}/sync?step=select_sync_path&id=${parentAccountId}_${accountId}`;
110
105
 
111
106
  logger.log(
@@ -137,147 +132,26 @@ exports.handler = async options => {
137
132
  },
138
133
  ]);
139
134
  if (!confirmed) {
135
+ trackCommandUsage('sandbox-sync', { successful: false }, accountId);
140
136
  process.exit(EXIT_CODES.SUCCESS);
141
137
  }
142
138
  }
143
139
  } else {
144
140
  logger.error('Sync must be run in a sandbox account.');
145
- process.exit(EXIT_CODES.ERROR);
146
- }
147
-
148
- let initiateSyncResponse;
149
-
150
- const baseUrl = getHubSpotWebsiteOrigin(
151
- getEnv(accountId) === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD
152
- );
153
- const syncStatusUrl = `${baseUrl}/sandboxes-developer/${parentAccountId}/${
154
- isDevelopmentSandbox ? 'development' : 'standard'
155
- }`;
156
-
157
- try {
158
- logger.log('');
159
- spinnies.add('sandboxSync', {
160
- text: i18n(`${i18nKey}.loading.startSync`),
161
- });
162
-
163
- // Fetches sync types based on default account. Parent account required for fetch
164
- const tasks = await getAvailableSyncTypes(
165
- parentAccountConfig,
166
- accountConfig
167
- );
168
-
169
- initiateSyncResponse = await initiateSync(
170
- parentAccountId,
171
- accountId,
172
- tasks,
173
- accountId
174
- );
175
-
176
- logger.log(i18n(`${i18nKey}.info.earlyExit`));
177
- logger.log('');
178
- spinnies.succeed('sandboxSync', {
179
- text: i18n(`${i18nKey}.loading.succeed`),
180
- });
181
- } catch (err) {
182
141
  trackCommandUsage('sandbox-sync', { successful: false }, accountId);
183
-
184
- spinnies.fail('sandboxSync', {
185
- text: i18n(`${i18nKey}.loading.fail`),
186
- });
187
-
188
- logger.log('');
189
- if (isMissingScopeError(err)) {
190
- logger.error(
191
- i18n(`${i18nKey}.failure.missingScopes`, {
192
- accountName: getAccountName(parentAccountConfig),
193
- })
194
- );
195
- } else if (
196
- isSpecifiedError(
197
- err,
198
- 429,
199
- 'RATE_LIMITS',
200
- 'sandboxes-sync-api.SYNC_IN_PROGRESS'
201
- )
202
- ) {
203
- logger.error(
204
- i18n(`${i18nKey}.failure.syncInProgress`, {
205
- url: `${baseUrl}/sandboxes-developer/${parentAccountId}/syncactivitylog`,
206
- })
207
- );
208
- } else if (
209
- isSpecifiedError(
210
- err,
211
- 403,
212
- 'BANNED',
213
- 'sandboxes-sync-api.SYNC_NOT_ALLOWED_INVALID_USERID'
214
- )
215
- ) {
216
- // This will only trigger if a user is not a super admin of the target account.
217
- logger.error(
218
- i18n(`${i18nKey}.failure.notSuperAdmin`, {
219
- account: getAccountName(accountConfig),
220
- })
221
- );
222
- } else if (
223
- isSpecifiedError(
224
- err,
225
- 404,
226
- 'OBJECT_NOT_FOUND',
227
- 'SandboxErrors.SANDBOX_NOT_FOUND'
228
- )
229
- ) {
230
- logger.error(
231
- i18n(`${i18nKey}.failure.objectNotFound`, {
232
- account: getAccountName(accountConfig),
233
- })
234
- );
235
- } else {
236
- logErrorInstance(err);
237
- }
238
- logger.log('');
239
-
240
142
  process.exit(EXIT_CODES.ERROR);
241
143
  }
242
144
 
243
145
  try {
244
- logger.log('');
245
- logger.log('Sync progress:');
246
- // Poll sync task status to show progress bars
247
- await pollSyncTaskStatus(
248
- parentAccountId,
249
- initiateSyncResponse.id,
250
- syncStatusUrl
251
- );
252
-
253
- logger.log('');
254
- spinnies.add('syncComplete', {
255
- text: i18n(`${i18nKey}.polling.syncing`),
256
- });
257
- spinnies.succeed('syncComplete', {
258
- text: i18n(`${i18nKey}.polling.succeed`),
146
+ await syncSandbox({
147
+ accountConfig,
148
+ parentAccountConfig,
149
+ env,
150
+ allowEarlyTermination: true,
259
151
  });
260
- logger.log('');
261
- logger.log(
262
- i18n(`${i18nKey}.info.syncStatus`, {
263
- url: syncStatusUrl,
264
- })
265
- );
266
-
267
152
  process.exit(EXIT_CODES.SUCCESS);
268
- } catch (err) {
269
- // If polling fails at this point, we do not track a failed sync since it is running in the background.
270
- logErrorInstance(err);
271
-
272
- spinnies.add('syncComplete', {
273
- text: i18n(`${i18nKey}.polling.syncing`),
274
- });
275
- spinnies.fail('syncComplete', {
276
- text: i18n(`${i18nKey}.polling.fail`, {
277
- url: syncStatusUrl,
278
- }),
279
- });
280
-
153
+ } catch (error) {
154
+ trackCommandUsage('sandbox-sync', { successful: false }, accountId);
281
155
  process.exit(EXIT_CODES.ERROR);
282
156
  }
283
157
  };
@@ -0,0 +1,66 @@
1
+ // https://github.com/npkgz/cli-progress/blob/master/README.md
2
+ const ProgressMultibarManager = require('cli-progress');
3
+
4
+ class CliProgressMultibarManager {
5
+ constructor() {
6
+ this.multibar = null;
7
+ this.barInstances = {};
8
+ }
9
+
10
+ init(options) {
11
+ if (!this.multibar) {
12
+ this.multibar = new ProgressMultibarManager.MultiBar(
13
+ {
14
+ hideCursor: true,
15
+ format: '[{bar}] {percentage}% | {label}',
16
+ gracefulExit: true,
17
+ ...options,
18
+ },
19
+ ProgressMultibarManager.Presets.rect
20
+ );
21
+ }
22
+
23
+ return {
24
+ get: this.get.bind(this),
25
+ create: this.create.bind(this),
26
+ update: this.update.bind(this),
27
+ increment: this.increment.bind(this),
28
+ remove: this.multibar.remove.bind(this.multibar),
29
+ stop: this.multibar.stop.bind(this.multibar),
30
+ log: this.multibar.log.bind(this.multibar),
31
+ };
32
+ }
33
+
34
+ get(barName) {
35
+ return this.barInstances[barName];
36
+ }
37
+
38
+ create(barName, total = 100, startValue = 0, options = {}) {
39
+ if (!this.multibar) {
40
+ return;
41
+ }
42
+ if (!this.barInstances[barName]) {
43
+ this.barInstances[barName] = this.multibar.create(
44
+ total,
45
+ startValue,
46
+ options
47
+ );
48
+ }
49
+ }
50
+
51
+ update(barName, value, options = {}) {
52
+ const barInstance = this.barInstances[barName];
53
+ if (barInstance) {
54
+ barInstance.update(value, options);
55
+ }
56
+ }
57
+
58
+ increment(barName, value, options = {}) {
59
+ const barInstance = this.barInstances[barName];
60
+ if (barInstance) {
61
+ barInstance.increment(value, options);
62
+ }
63
+ }
64
+ }
65
+
66
+ module.exports = new CliProgressMultibarManager();
@@ -1,12 +1,14 @@
1
1
  const { updateDefaultAccount } = require('@hubspot/cli-lib/lib/config');
2
2
  const { promptUser } = require('./promptUtils');
3
3
  const { i18n } = require('@hubspot/cli-lib/lib/lang');
4
- const { getSandboxType } = require('../sandboxes');
4
+ const { getSandboxTypeAsString } = require('../sandboxes');
5
5
 
6
6
  const mapAccountChoices = portals =>
7
7
  portals.map(p => {
8
8
  const isSandbox = p.sandboxAccountType && p.sandboxAccountType !== null;
9
- const sandboxName = `[${getSandboxType(p.sandboxAccountType)} sandbox] `;
9
+ const sandboxName = `[${getSandboxTypeAsString(
10
+ p.sandboxAccountType
11
+ )} sandbox] `;
10
12
  return {
11
13
  name: `${p.name} ${isSandbox ? sandboxName : ''}(${p.portalId})`,
12
14
  value: p.name || p.portalId,
@@ -15,14 +17,14 @@ const mapAccountChoices = portals =>
15
17
 
16
18
  const i18nKey = 'cli.commands.accounts.subcommands.use';
17
19
 
18
- const selectAccountFromConfig = async config => {
20
+ const selectAccountFromConfig = async (config, prompt) => {
19
21
  const { default: selectedDefault } = await promptUser([
20
22
  {
21
23
  type: 'list',
22
24
  look: false,
23
25
  name: 'default',
24
26
  pageSize: 20,
25
- message: i18n(`${i18nKey}.promptMessage`),
27
+ message: prompt || i18n(`${i18nKey}.promptMessage`),
26
28
  choices: mapAccountChoices(config.portals),
27
29
  default: config.defaultPortal,
28
30
  },
@@ -66,7 +66,7 @@ const projectLogsPrompt = (accountId, promptOptions = {}) => {
66
66
 
67
67
  if (deployedBuild && deployedBuild.subbuildStatuses) {
68
68
  return deployedBuild.subbuildStatuses
69
- .filter(subbuild => subbuild.buildType === 'APP')
69
+ .filter(subbuild => subbuild.buildType === 'PRIVATE_APP')
70
70
  .map(subbuild => ({
71
71
  name: subbuild.buildName,
72
72
  value: subbuild.buildName,
@@ -1,6 +1,7 @@
1
1
  const { promptUser } = require('./promptUtils');
2
2
  const { i18n } = require('@hubspot/cli-lib/lib/lang');
3
- const { getSandboxType } = require('../sandboxes');
3
+ const { getSandboxTypeAsString } = require('../sandboxes');
4
+ const { accountNameExistsInConfig } = require('@hubspot/cli-lib/lib/config');
4
5
 
5
6
  const i18nKey = 'cli.lib.prompts.sandboxesPrompt';
6
7
 
@@ -8,7 +9,9 @@ const mapSandboxAccountChoices = portals =>
8
9
  portals
9
10
  .filter(p => p.sandboxAccountType && p.sandboxAccountType !== null)
10
11
  .map(p => {
11
- const sandboxName = `[${getSandboxType(p.sandboxAccountType)} sandbox] `;
12
+ const sandboxName = `[${getSandboxTypeAsString(
13
+ p.sandboxAccountType
14
+ )} sandbox] `;
12
15
  return {
13
16
  name: `${p.name} ${sandboxName}(${p.portalId})`,
14
17
  value: p.name || p.portalId,
@@ -27,22 +30,50 @@ const mapNonSandboxAccountChoices = portals =>
27
30
  };
28
31
  });
29
32
 
30
- const createSandboxPrompt = () => {
33
+ const sandboxNamePrompt = () => {
31
34
  return promptUser([
32
35
  {
33
36
  name: 'name',
34
- message: i18n(`${i18nKey}.enterName`),
37
+ message: i18n(`${i18nKey}.name.message`),
35
38
  validate(val) {
36
39
  if (typeof val !== 'string') {
37
- return i18n(`${i18nKey}.errors.invalidName`);
40
+ return i18n(`${i18nKey}.name.errors.invalidName`);
41
+ } else if (!val.length) {
42
+ return i18n(`${i18nKey}.name.errors.nameRequired`);
38
43
  }
39
- return true;
44
+ return accountNameExistsInConfig(val)
45
+ ? i18n(`${i18nKey}.name.errors.accountNameExists`, { name: val })
46
+ : true;
40
47
  },
41
48
  default: 'New sandbox',
42
49
  },
43
50
  ]);
44
51
  };
45
52
 
53
+ const sandboxTypeChoices = [
54
+ {
55
+ name: i18n(`${i18nKey}.type.developer`),
56
+ value: 'DEVELOPER',
57
+ },
58
+ {
59
+ name: i18n(`${i18nKey}.type.standard`),
60
+ value: 'STANDARD',
61
+ },
62
+ ];
63
+
64
+ const sandboxTypePrompt = () => {
65
+ return promptUser([
66
+ {
67
+ name: 'type',
68
+ message: i18n(`${i18nKey}.type.message`),
69
+ type: 'list',
70
+ look: false,
71
+ choices: sandboxTypeChoices,
72
+ default: 'DEVELOPER',
73
+ },
74
+ ]);
75
+ };
76
+
46
77
  const deleteSandboxPrompt = (config, promptParentAccount = false) => {
47
78
  const choices = promptParentAccount
48
79
  ? mapNonSandboxAccountChoices(config.portals)
@@ -55,8 +86,8 @@ const deleteSandboxPrompt = (config, promptParentAccount = false) => {
55
86
  name: 'account',
56
87
  message: i18n(
57
88
  promptParentAccount
58
- ? `${i18nKey}.selectParentAccountName`
59
- : `${i18nKey}.selectAccountName`
89
+ ? `${i18nKey}.name.selectParentAccountName`
90
+ : `${i18nKey}.name.selectAccountName`
60
91
  ),
61
92
  type: 'list',
62
93
  look: false,
@@ -68,7 +99,7 @@ const deleteSandboxPrompt = (config, promptParentAccount = false) => {
68
99
  };
69
100
 
70
101
  module.exports = {
71
- createSandboxPrompt,
102
+ sandboxNamePrompt,
103
+ sandboxTypePrompt,
72
104
  deleteSandboxPrompt,
73
- getSandboxType,
74
105
  };