@hubspot/cli 5.4.0 → 6.0.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.
Files changed (35) hide show
  1. package/commands/__tests__/projects.test.js +105 -0
  2. package/commands/accounts/clean.js +1 -1
  3. package/commands/project/__tests__/deploy.test.js +1 -1
  4. package/commands/project/__tests__/installDeps.test.js +168 -0
  5. package/commands/project/__tests__/logs.test.js +305 -0
  6. package/commands/project/cloneApp.js +3 -16
  7. package/commands/project/deploy.js +4 -1
  8. package/commands/project/dev.js +15 -6
  9. package/commands/project/download.js +4 -1
  10. package/commands/project/installDeps.js +78 -0
  11. package/commands/project/logs.js +80 -242
  12. package/commands/project/migrateApp.js +3 -6
  13. package/commands/project/upload.js +5 -3
  14. package/commands/project/watch.js +3 -9
  15. package/commands/project.js +2 -0
  16. package/commands/sandbox/create.js +1 -0
  17. package/commands/sandbox.js +0 -2
  18. package/lang/en.lyaml +25 -70
  19. package/lib/LocalDevManager.js +1 -22
  20. package/lib/__tests__/dependencyManagement.test.js +245 -0
  21. package/lib/__tests__/projectLogsManager.test.js +210 -0
  22. package/lib/dependencyManagement.js +157 -0
  23. package/lib/errorHandlers/apiErrors.js +1 -3
  24. package/lib/errorHandlers/overrideErrors.js +57 -36
  25. package/lib/localDev.js +1 -7
  26. package/lib/projectLogsManager.js +144 -0
  27. package/lib/projects.js +3 -6
  28. package/lib/projectsWatch.js +2 -5
  29. package/lib/prompts/__tests__/projectsLogsPrompt.test.js +46 -0
  30. package/lib/prompts/createProjectPrompt.js +4 -0
  31. package/lib/prompts/projectDevTargetAccountPrompt.js +16 -25
  32. package/lib/prompts/projectsLogsPrompt.js +17 -108
  33. package/lib/sandboxSync.js +13 -15
  34. package/package.json +6 -6
  35. package/commands/sandbox/sync.js +0 -225
@@ -1,120 +1,29 @@
1
1
  const { i18n } = require('../lang');
2
- const { fetchProject } = require('@hubspot/local-dev-lib/api/projects');
3
2
  const { promptUser } = require('./promptUtils');
4
- const { getAccountId } = require('../commonOpts');
5
- const { getProjectConfig, ensureProjectExists } = require('../projects');
6
- const {
7
- logApiErrorInstance,
8
- ApiErrorContext,
9
- } = require('../../lib/errorHandlers/apiErrors');
10
- const { logger } = require('@hubspot/local-dev-lib/logger');
11
- const { EXIT_CODES } = require('../enums/exitCodes');
12
3
 
13
4
  const i18nKey = 'lib.prompts.projectLogsPrompt';
14
5
 
15
- const SERVERLESS_FUNCTION_TYPES = {
16
- APP_FUNCTION: 'app-function',
17
- PUBLIC_ENDPOINT: 'public-endpoint',
18
- };
6
+ const projectLogsPrompt = async ({
7
+ functionChoices,
8
+ promptOptions,
9
+ projectName = {},
10
+ }) => {
11
+ if (!functionChoices) {
12
+ return {};
13
+ }
14
+ if (functionChoices && functionChoices.length === 1) {
15
+ return { functionName: functionChoices[0] };
16
+ }
19
17
 
20
- const projectLogsPrompt = (accountId, promptOptions = {}) => {
21
18
  return promptUser([
22
- {
23
- name: 'projectName',
24
- message: i18n(`${i18nKey}.projectName.message`),
25
- when: !promptOptions.project,
26
- default: async () => {
27
- const { projectConfig } = await getProjectConfig();
28
- return projectConfig && projectConfig.name ? projectConfig.name : null;
29
- },
30
- validate: name =>
31
- !name.length ? i18n(`${i18nKey}.projectName.error`) : true,
32
- },
33
- {
34
- name: 'logType',
35
- type: 'list',
36
- message: i18n(`${i18nKey}.logType.message`),
37
- when:
38
- !promptOptions.app &&
39
- !promptOptions.function &&
40
- !promptOptions.endpoint,
41
- choices: [
42
- {
43
- name: i18n(`${i18nKey}.logType.function`),
44
- value: SERVERLESS_FUNCTION_TYPES.APP_FUNCTION,
45
- },
46
- {
47
- name: i18n(`${i18nKey}.logType.endpoint`),
48
- value: SERVERLESS_FUNCTION_TYPES.PUBLIC_ENDPOINT,
49
- },
50
- ],
51
- },
52
- {
53
- name: 'appName',
54
- type: 'list',
55
- message: i18n(`${i18nKey}.appName`),
56
- when: ({ logType }) => {
57
- return (
58
- (promptOptions.function ||
59
- logType === SERVERLESS_FUNCTION_TYPES.APP_FUNCTION) &&
60
- !promptOptions.app &&
61
- !promptOptions.endpoint
62
- );
63
- },
64
- choices: async ({ projectName }) => {
65
- const name = projectName || promptOptions.project;
66
-
67
- try {
68
- await ensureProjectExists(accountId, name, {
69
- allowCreate: false,
70
- });
71
- const { deployedBuild } = await fetchProject(accountId, name);
72
-
73
- if (deployedBuild && deployedBuild.subbuildStatuses) {
74
- return deployedBuild.subbuildStatuses
75
- .filter(subbuild => subbuild.buildType === 'PRIVATE_APP')
76
- .map(subbuild => ({
77
- name: subbuild.buildName,
78
- value: subbuild.buildName,
79
- }));
80
- } else {
81
- logger.debug('Failed to fetch project');
82
- process.exit(EXIT_CODES.ERROR);
83
- }
84
- } catch (e) {
85
- const { projectConfig } = await getProjectConfig();
86
- const projectName = projectConfig.name;
87
-
88
- logApiErrorInstance(
89
- e,
90
- new ApiErrorContext({ accountId: getAccountId(), projectName })
91
- );
92
- process.exit(EXIT_CODES.ERROR);
93
- }
94
- },
95
- },
96
19
  {
97
20
  name: 'functionName',
98
- message: i18n(`${i18nKey}.functionName`),
99
- when: ({ logType }) => {
100
- return (
101
- (promptOptions.app ||
102
- logType === SERVERLESS_FUNCTION_TYPES.APP_FUNCTION) &&
103
- !promptOptions.function &&
104
- !promptOptions.endpoint
105
- );
106
- },
107
- },
108
- {
109
- name: 'endpointName',
110
- message: i18n(`${i18nKey}.endpointName`),
111
- when: ({ logType }) => {
112
- return (
113
- logType === SERVERLESS_FUNCTION_TYPES.PUBLIC_ENDPOINT &&
114
- !promptOptions.function &&
115
- !promptOptions.endpoint
116
- );
117
- },
21
+ type: 'list',
22
+ message: i18n(`${i18nKey}.functionName`, { projectName }),
23
+ when: () =>
24
+ (!promptOptions || !promptOptions.function) &&
25
+ functionChoices.length > 0,
26
+ choices: functionChoices,
118
27
  },
119
28
  ]);
120
29
  };
@@ -4,14 +4,12 @@ const { logger } = require('@hubspot/local-dev-lib/logger');
4
4
  const { i18n } = require('./lang');
5
5
  const { getAvailableSyncTypes } = require('./sandboxes');
6
6
  const { initiateSync } = require('@hubspot/local-dev-lib/sandboxes');
7
+ const { debugErrorAndContext } = require('./errorHandlers/standardErrors');
7
8
  const {
8
- debugErrorAndContext,
9
- logErrorInstance,
10
- } = require('./errorHandlers/standardErrors');
11
- const {
12
- isSpecifiedError,
13
- isMissingScopeError,
14
- } = require('@hubspot/local-dev-lib/errors/apiErrors');
9
+ logApiErrorInstance,
10
+ ApiErrorContext,
11
+ } = require('./errorHandlers/apiErrors');
12
+ const { isSpecifiedError } = require('@hubspot/local-dev-lib/errors/apiErrors');
15
13
  const { getSandboxTypeAsString } = require('./sandboxes');
16
14
  const { getAccountId } = require('@hubspot/local-dev-lib/config');
17
15
  const {
@@ -97,13 +95,7 @@ const syncSandbox = async ({
97
95
  });
98
96
 
99
97
  logger.log('');
100
- if (isMissingScopeError(err)) {
101
- logger.error(
102
- i18n(`${i18nKey}.failure.missingScopes`, {
103
- accountName: uiAccountDescription(parentAccountId),
104
- })
105
- );
106
- } else if (
98
+ if (
107
99
  isSpecifiedError(err, {
108
100
  statusCode: 403,
109
101
  category: 'BANNED',
@@ -163,7 +155,13 @@ const syncSandbox = async ({
163
155
  'https://app.hubspot.com/l/docs/guides/crm/project-cli-commands#developer-projects-cli-commands-beta'
164
156
  );
165
157
  } else {
166
- logErrorInstance(err);
158
+ logApiErrorInstance(
159
+ err,
160
+ new ApiErrorContext({
161
+ accountId: parentAccountId,
162
+ request: 'sandbox sync',
163
+ })
164
+ );
167
165
  }
168
166
  logger.log('');
169
167
  throw err;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubspot/cli",
3
- "version": "5.4.0",
3
+ "version": "6.0.0",
4
4
  "description": "CLI for working with HubSpot",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -8,10 +8,10 @@
8
8
  "url": "https://github.com/HubSpot/hubspot-cms-tools"
9
9
  },
10
10
  "dependencies": {
11
- "@hubspot/local-dev-lib": "1.10.0",
12
- "@hubspot/serverless-dev-runtime": "5.3.0",
11
+ "@hubspot/local-dev-lib": "1.13.0",
12
+ "@hubspot/serverless-dev-runtime": "6.0.0",
13
13
  "@hubspot/theme-preview-dev-server": "0.0.7",
14
- "@hubspot/ui-extensions-dev-server": "0.8.30",
14
+ "@hubspot/ui-extensions-dev-server": "0.8.33",
15
15
  "archiver": "^5.3.0",
16
16
  "chalk": "^4.1.2",
17
17
  "chokidar": "^3.0.1",
@@ -37,7 +37,7 @@
37
37
  "mock-stdin": "^1.0.0"
38
38
  },
39
39
  "engines": {
40
- "node": ">=16"
40
+ "node": ">=18"
41
41
  },
42
42
  "bin": {
43
43
  "hs": "./bin/hs",
@@ -46,5 +46,5 @@
46
46
  "publishConfig": {
47
47
  "access": "public"
48
48
  },
49
- "gitHead": "eb76ce9051e5f44c45e8c763930439c168a489ec"
49
+ "gitHead": "d01e7f7c6222133ffac7c6dd757fb95247a04b25"
50
50
  }
@@ -1,225 +0,0 @@
1
- const {
2
- addAccountOptions,
3
- addConfigOptions,
4
- getAccountId,
5
- addUseEnvironmentOptions,
6
- addTestingOptions,
7
- } = require('../../lib/commonOpts');
8
- const { trackCommandUsage } = require('../../lib/usageTracking');
9
- const { logger } = require('@hubspot/local-dev-lib/logger');
10
- const { loadAndValidateOptions } = require('../../lib/validation');
11
- const { i18n } = require('../../lib/lang');
12
- const { EXIT_CODES } = require('../../lib/enums/exitCodes');
13
- const { getAccountConfig, getEnv } = require('@hubspot/local-dev-lib/config');
14
- const { getHubSpotWebsiteOrigin } = require('@hubspot/local-dev-lib/urls');
15
- const { promptUser } = require('../../lib/prompts/promptUtils');
16
- const {
17
- uiLine,
18
- uiAccountDescription,
19
- uiDeprecatedMessage,
20
- uiDeprecatedDescription,
21
- } = require('../../lib/ui');
22
- const {
23
- isSandbox,
24
- isStandardSandbox,
25
- isDevelopmentSandbox,
26
- } = require('../../lib/accountTypes');
27
- const {
28
- getAvailableSyncTypes,
29
- getSyncTypesWithContactRecordsPrompt,
30
- } = require('../../lib/sandboxes');
31
- const { syncSandbox } = require('../../lib/sandboxSync');
32
- const { getValidEnv } = require('@hubspot/local-dev-lib/environment');
33
- const { isSpecifiedError } = require('@hubspot/local-dev-lib/errors/apiErrors');
34
- const { logErrorInstance } = require('../../lib/errorHandlers/standardErrors');
35
- const {
36
- HUBSPOT_ACCOUNT_TYPE_STRINGS,
37
- HUBSPOT_ACCOUNT_TYPES,
38
- } = require('@hubspot/local-dev-lib/constants/config');
39
-
40
- const i18nKey = 'commands.sandbox.subcommands.sync';
41
-
42
- exports.command = 'sync';
43
- exports.describe = uiDeprecatedDescription(
44
- i18n(`${i18nKey}.describe`),
45
- 'hs sandbox sync'
46
- );
47
-
48
- exports.handler = async options => {
49
- await loadAndValidateOptions(options);
50
-
51
- uiDeprecatedMessage('hs sandbox sync');
52
-
53
- const { force } = options; // For scripting purposes
54
- const accountId = getAccountId(options);
55
- const accountConfig = getAccountConfig(accountId);
56
- const env = getValidEnv(getEnv(accountId));
57
-
58
- trackCommandUsage(
59
- 'sandbox-sync',
60
- { type: accountConfig.accountType },
61
- accountId
62
- );
63
-
64
- if (
65
- // Check if default account is a sandbox, otherwise exit
66
- !isSandbox(accountConfig)
67
- ) {
68
- logger.error(
69
- i18n(`${i18nKey}.failure.invalidAccountType`, {
70
- accountType:
71
- HUBSPOT_ACCOUNT_TYPE_STRINGS[
72
- HUBSPOT_ACCOUNT_TYPES[accountConfig.accountType]
73
- ],
74
- })
75
- );
76
- process.exit(EXIT_CODES.ERROR);
77
- }
78
-
79
- // Verify parent account exists in the config
80
- let parentAccountId = accountConfig.parentAccountId || undefined;
81
- if (!parentAccountId || !getAccountId({ account: parentAccountId })) {
82
- logger.log('');
83
- logger.error(
84
- i18n(`${i18nKey}.failure.missingParentPortal`, {
85
- sandboxName: uiAccountDescription(accountId),
86
- })
87
- );
88
- process.exit(EXIT_CODES.ERROR);
89
- }
90
-
91
- const parentAccountConfig = getAccountConfig(parentAccountId);
92
-
93
- let availableSyncTasks;
94
- try {
95
- availableSyncTasks = await getAvailableSyncTypes(
96
- parentAccountConfig,
97
- accountConfig
98
- );
99
- } catch (error) {
100
- if (
101
- isSpecifiedError(error, {
102
- statusCode: 404,
103
- category: 'OBJECT_NOT_FOUND',
104
- subCategory: 'SandboxErrors.SANDBOX_NOT_FOUND',
105
- })
106
- ) {
107
- logger.error(
108
- i18n('lib.sandbox.sync.failure.objectNotFound', {
109
- account: uiAccountDescription(accountId),
110
- })
111
- );
112
- } else {
113
- logErrorInstance(error);
114
- }
115
- process.exit(EXIT_CODES.ERROR);
116
- }
117
-
118
- if (isDevelopmentSandbox(accountConfig)) {
119
- logger.log(i18n(`${i18nKey}.info.developmentSandbox`));
120
- logger.log(
121
- i18n(`${i18nKey}.info.sync`, {
122
- parentAccountName: uiAccountDescription(parentAccountId),
123
- sandboxName: uiAccountDescription(accountId),
124
- })
125
- );
126
- uiLine();
127
- logger.warn(i18n(`${i18nKey}.warning.developmentSandbox`));
128
- uiLine();
129
- logger.log('');
130
-
131
- if (!force) {
132
- // Skip confirmation if force flag is present.
133
- const { confirmSandboxSyncPrompt: confirmed } = await promptUser([
134
- {
135
- name: 'confirmSandboxSyncPrompt',
136
- type: 'confirm',
137
- message: i18n(`${i18nKey}.confirm.developmentSandbox`, {
138
- parentAccountName: uiAccountDescription(parentAccountId),
139
- sandboxName: uiAccountDescription(accountId),
140
- }),
141
- },
142
- ]);
143
- if (!confirmed) {
144
- process.exit(EXIT_CODES.SUCCESS);
145
- }
146
- }
147
- } else if (isStandardSandbox(accountConfig)) {
148
- const standardSyncUrl = `${getHubSpotWebsiteOrigin(
149
- env
150
- )}/sandboxes-developer/${parentAccountId}/sync?step=select_sync_path&id=${parentAccountId}_${accountId}`;
151
-
152
- logger.log(
153
- i18n(`${i18nKey}.info.standardSandbox`, {
154
- url: standardSyncUrl,
155
- })
156
- );
157
- logger.log(
158
- i18n(`${i18nKey}.info.sync`, {
159
- parentAccountName: uiAccountDescription(parentAccountId),
160
- sandboxName: uiAccountDescription(accountId),
161
- })
162
- );
163
- uiLine();
164
- logger.warn(i18n(`${i18nKey}.warning.standardSandbox`));
165
- uiLine();
166
- logger.log('');
167
-
168
- if (!force) {
169
- // Skip confirmation if force flag is present.
170
- const { confirmSandboxSyncPrompt: confirmed } = await promptUser([
171
- {
172
- name: 'confirmSandboxSyncPrompt',
173
- type: 'confirm',
174
- message: i18n(`${i18nKey}.confirm.standardSandbox`, {
175
- parentAccountName: uiAccountDescription(parentAccountId),
176
- sandboxName: uiAccountDescription(accountId),
177
- }),
178
- },
179
- ]);
180
- if (!confirmed) {
181
- process.exit(EXIT_CODES.SUCCESS);
182
- }
183
- }
184
- } else {
185
- logger.error('Sync must be run in a sandbox account.');
186
- process.exit(EXIT_CODES.ERROR);
187
- }
188
-
189
- try {
190
- const syncTasks = await getSyncTypesWithContactRecordsPrompt(
191
- accountConfig,
192
- availableSyncTasks,
193
- force
194
- );
195
-
196
- await syncSandbox({
197
- accountConfig,
198
- parentAccountConfig,
199
- env,
200
- syncTasks,
201
- allowEarlyTermination: true,
202
- });
203
-
204
- process.exit(EXIT_CODES.SUCCESS);
205
- } catch (error) {
206
- process.exit(EXIT_CODES.ERROR);
207
- }
208
- };
209
-
210
- exports.builder = yargs => {
211
- yargs.option('f', {
212
- type: 'boolean',
213
- alias: 'force',
214
- describe: i18n(`${i18nKey}.examples.force`),
215
- });
216
-
217
- yargs.example([['$0 sandbox sync', i18n(`${i18nKey}.examples.default`)]]);
218
-
219
- addConfigOptions(yargs);
220
- addAccountOptions(yargs);
221
- addUseEnvironmentOptions(yargs);
222
- addTestingOptions(yargs);
223
-
224
- return yargs;
225
- };