@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
@@ -86,11 +86,20 @@ exports.handler = async options => {
86
86
  validateProjectConfig(projectConfig, projectDir);
87
87
 
88
88
  const components = await findProjectComponents(projectDir);
89
- const componentTypes = getProjectComponentTypes(components);
89
+ const runnableComponents = components.filter(component => component.runnable);
90
+ const componentTypes = getProjectComponentTypes(runnableComponents);
90
91
  const hasPrivateApps = !!componentTypes[COMPONENT_TYPES.privateApp];
91
92
  const hasPublicApps = !!componentTypes[COMPONENT_TYPES.publicApp];
92
93
 
93
- if (hasPrivateApps && hasPublicApps) {
94
+ if (runnableComponents.length === 0) {
95
+ logger.error(
96
+ i18n(`${i18nKey}.errors.noRunnableComponents`, {
97
+ projectDir,
98
+ command: uiCommandReference('hs project add'),
99
+ })
100
+ );
101
+ process.exit(EXIT_CODES.SUCCESS);
102
+ } else if (hasPrivateApps && hasPublicApps) {
94
103
  logger.error(i18n(`${i18nKey}.errors.invalidProjectComponents`));
95
104
  process.exit(EXIT_CODES.SUCCESS);
96
105
  }
@@ -114,9 +123,6 @@ exports.handler = async options => {
114
123
  }
115
124
  }
116
125
 
117
- let createNewSandbox = false;
118
- let createNewDeveloperTestAccount = false;
119
-
120
126
  // The user is targeting an account type that we recommend developing on
121
127
  if (!targetProjectAccountId && defaultAccountIsRecommendedType) {
122
128
  targetTestingAccountId = accountId;
@@ -145,6 +151,9 @@ exports.handler = async options => {
145
151
  checkIfAppDeveloperAccount(accountConfig);
146
152
  }
147
153
 
154
+ let createNewSandbox = false;
155
+ let createNewDeveloperTestAccount = false;
156
+
148
157
  if (!targetProjectAccountId) {
149
158
  const {
150
159
  targetAccountId,
@@ -224,7 +233,7 @@ exports.handler = async options => {
224
233
  }
225
234
 
226
235
  const LocalDev = new LocalDevManager({
227
- components,
236
+ runnableComponents,
228
237
  debug: options.debug,
229
238
  deployedBuild,
230
239
  isGithubLinked,
@@ -108,7 +108,10 @@ exports.handler = async options => {
108
108
  );
109
109
  process.exit(EXIT_CODES.SUCCESS);
110
110
  } catch (e) {
111
- logApiErrorInstance(e, new ApiErrorContext({ accountId, projectName }));
111
+ logApiErrorInstance(
112
+ e,
113
+ new ApiErrorContext({ accountId, request: 'project download' })
114
+ );
112
115
  process.exit(EXIT_CODES.ERROR);
113
116
  }
114
117
  };
@@ -0,0 +1,78 @@
1
+ const {
2
+ installPackages,
3
+ getProjectPackageJsonLocations,
4
+ } = require('../../lib/dependencyManagement');
5
+ const { logger } = require('@hubspot/local-dev-lib/logger');
6
+ const { EXIT_CODES } = require('../../lib/enums/exitCodes');
7
+ const { getProjectConfig } = require('../../lib/projects');
8
+ const { promptUser } = require('../../lib/prompts/promptUtils');
9
+ const path = require('path');
10
+ const { i18n } = require('../../lib/lang');
11
+ const { trackCommandUsage } = require('../../lib/usageTracking');
12
+ const { getAccountId } = require('../../lib/commonOpts');
13
+
14
+ const i18nKey = `commands.project.subcommands.installDeps`;
15
+
16
+ exports.command = 'install-deps [packages..]';
17
+ // Intentionally making this null to hide command
18
+ exports.describe = null;
19
+ // exports.describe = uiBetaTag(i18n(`${i18nKey}.help.describe`), false);
20
+
21
+ exports.handler = async ({ packages }) => {
22
+ try {
23
+ const accountId = getAccountId();
24
+ trackCommandUsage('project-install-deps', null, accountId);
25
+
26
+ const projectConfig = await getProjectConfig();
27
+ if (!projectConfig || !projectConfig.projectDir) {
28
+ logger.error(i18n(`${i18nKey}.noProjectConfig`));
29
+ return process.exit(EXIT_CODES.ERROR);
30
+ }
31
+
32
+ const { projectDir } = projectConfig;
33
+
34
+ let installLocations = await getProjectPackageJsonLocations();
35
+ if (packages) {
36
+ const { selectedInstallLocations } = await promptUser([
37
+ {
38
+ name: 'selectedInstallLocations',
39
+ type: 'checkbox',
40
+ when: () => packages && packages.length > 0,
41
+ message: i18n(`${i18nKey}.installLocationPrompt`),
42
+ choices: installLocations.map(dir => ({
43
+ name: path.relative(projectDir, dir),
44
+ value: dir,
45
+ })),
46
+ validate: choices => {
47
+ if (choices === undefined || choices.length === 0) {
48
+ return i18n(`${i18nKey}.installLocationPromptRequired`);
49
+ }
50
+ return true;
51
+ },
52
+ },
53
+ ]);
54
+ if (selectedInstallLocations) {
55
+ installLocations = selectedInstallLocations;
56
+ }
57
+ }
58
+
59
+ await installPackages({
60
+ packages,
61
+ installLocations,
62
+ });
63
+ } catch (e) {
64
+ logger.debug(e);
65
+ logger.error(e.message);
66
+ return process.exit(EXIT_CODES.ERROR);
67
+ }
68
+ };
69
+
70
+ exports.builder = yargs => {
71
+ yargs.example([
72
+ ['$0 project install-deps', i18n(`${i18nKey}.help.installAppDepsExample`)],
73
+ [
74
+ '$0 project install-deps dependency1 dependency2',
75
+ i18n(`${i18nKey}.help.addDepToSubComponentExample`),
76
+ ],
77
+ ]);
78
+ };
@@ -4,253 +4,111 @@ const {
4
4
  ENVIRONMENTS,
5
5
  } = require('@hubspot/local-dev-lib/constants/environments');
6
6
  const {
7
- addAccountOptions,
8
- addConfigOptions,
9
7
  getAccountId,
10
8
  addUseEnvironmentOptions,
11
9
  } = require('../../lib/commonOpts');
12
10
  const { trackCommandUsage } = require('../../lib/usageTracking');
13
11
  const { logger } = require('@hubspot/local-dev-lib/logger');
14
- // const { outputLogs } = require('../../lib/ui/serverlessFunctionLogs');
15
- const {
16
- fetchProject,
17
- fetchDeployComponentsMetadata,
18
- } = require('@hubspot/local-dev-lib/api/projects');
19
12
  const { getTableContents, getTableHeader } = require('../../lib/ui/table');
20
- // const {
21
- // logApiErrorInstance,
22
- // ApiErrorContext,
23
- // } = require('../../lib/errorHandlers/apiErrors');
24
- // const {
25
- // getFunctionLogs,
26
- // getLatestFunctionLog,
27
- // getProjectAppFunctionLogs,
28
- // getLatestProjectAppFunctionLog,
29
- // } = require('@hubspot/local-dev-lib/api/functions');
13
+ const { logApiErrorInstance } = require('../../lib/errorHandlers/apiErrors');
30
14
 
31
- const { ensureProjectExists } = require('../../lib/projects');
32
15
  const { loadAndValidateOptions } = require('../../lib/validation');
33
16
  const { uiBetaTag, uiLine, uiLink } = require('../../lib/ui');
34
17
  const { projectLogsPrompt } = require('../../lib/prompts/projectsLogsPrompt');
35
- // const { tailLogs } = require('../../lib/serverlessLogs');
36
18
  const { i18n } = require('../../lib/lang');
37
- // const { EXIT_CODES } = require('../../lib/enums/exitCodes');
19
+ const { EXIT_CODES } = require('../../lib/enums/exitCodes');
20
+ const ProjectLogsManager = require('../../lib/projectLogsManager');
38
21
 
39
22
  const i18nKey = 'commands.project.subcommands.logs';
40
23
 
41
24
  const getPrivateAppsUrl = accountId => {
42
25
  const baseUrl = getHubSpotWebsiteOrigin(
43
- getEnv() === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD
26
+ getEnv(accountId) === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD
44
27
  );
45
28
 
46
29
  return `${baseUrl}/private-apps/${accountId}`;
47
30
  };
48
31
 
49
- // We currently cannot fetch logs directly to the CLI. See internal CLI issue #413 for more information.
50
-
51
- // const handleLogsError = (e, name, projectName) => {
52
- // if (e.response && e.response.status === 404) {
53
- // logger.debug(`Log fetch error: ${e.message}`);
54
- // logger.log(i18n(`${i18nKey}.logs.noLogsFound`, { name }));
55
- // } else {
56
- // logApiErrorInstance(
57
- // e,
58
- // new ApiErrorContext({ accountId: getAccountId(), projectName })
59
- // );
60
- // process.exit(EXIT_CODES.ERROR);
61
- // }
62
- // };
63
-
64
- // const handleFunctionLog = async (accountId, options) => {
65
- // const {
66
- // latest,
67
- // follow,
68
- // compact,
69
- // appPath,
70
- // functionName,
71
- // projectName,
72
- // } = options;
73
-
74
- // let logsResp;
75
-
76
- // const tailCall = async after => {
77
- // try {
78
- // return appPath
79
- // ? getProjectAppFunctionLogs(
80
- // accountId,
81
- // functionName,
82
- // projectName,
83
- // appPath,
84
- // {
85
- // after,
86
- // }
87
- // )
88
- // : getFunctionLogs(accountId, functionName, { after });
89
- // } catch (e) {
90
- // handleLogsError(e, functionName, projectName);
91
- // }
92
- // };
93
-
94
- // const fetchLatest = async () => {
95
- // return appPath
96
- // ? getLatestProjectAppFunctionLog(
97
- // accountId,
98
- // functionName,
99
- // projectName,
100
- // appPath
101
- // )
102
- // : getLatestFunctionLog(accountId, functionName, projectName);
103
- // };
104
-
105
- // if (follow) {
106
- // await tailLogs({
107
- // accountId,
108
- // compact,
109
- // tailCall,
110
- // fetchLatest,
111
- // name: functionName,
112
- // });
113
- // } else if (latest) {
114
- // try {
115
- // logsResp = await fetchLatest();
116
- // } catch (e) {
117
- // handleLogsError(e, functionName, projectName);
118
- // return true;
119
- // }
120
- // } else {
121
- // try {
122
- // logsResp = await tailCall();
123
- // } catch (e) {
124
- // handleLogsError(e, functionName, projectName);
125
- // return true;
126
- // }
127
- // }
128
-
129
- // if (logsResp) {
130
- // outputLogs(logsResp, options);
131
- // return true;
132
- // }
133
- // return false;
134
- // };
32
+ function logTable(tableHeader, logsInfo) {
33
+ logger.log(i18n(`${i18nKey}.logs.showingLogs`));
34
+ logger.log(
35
+ getTableContents([tableHeader, logsInfo], { border: { bodyLeft: ' ' } })
36
+ );
37
+ }
38
+
39
+ function logPreamble() {
40
+ if (ProjectLogsManager.isPublicFunction) {
41
+ logTable(
42
+ getTableHeader([
43
+ i18n(`${i18nKey}.table.accountHeader`),
44
+ i18n(`${i18nKey}.table.functionHeader`),
45
+ i18n(`${i18nKey}.table.endpointHeader`),
46
+ ]),
47
+ [
48
+ ProjectLogsManager.accountId,
49
+ ProjectLogsManager.functionName,
50
+ ProjectLogsManager.endpointName,
51
+ ]
52
+ );
53
+ logger.log(
54
+ uiLink(
55
+ i18n(`${i18nKey}.logs.hubspotLogsDirectLink`),
56
+ `${getPrivateAppsUrl(ProjectLogsManager.accountId)}/${
57
+ ProjectLogsManager.appId
58
+ }/logs/serverlessGatewayExecution?path=${
59
+ ProjectLogsManager.endpointName
60
+ }`
61
+ )
62
+ );
63
+ } else {
64
+ logTable(
65
+ getTableHeader([
66
+ i18n(`${i18nKey}.table.accountHeader`),
67
+ i18n(`${i18nKey}.table.functionHeader`),
68
+ ]),
69
+ [ProjectLogsManager.accountId, ProjectLogsManager.functionName]
70
+ );
71
+ logger.log(
72
+ uiLink(
73
+ i18n(`${i18nKey}.logs.hubspotLogsDirectLink`),
74
+ `${getPrivateAppsUrl(ProjectLogsManager.accountId)}/${
75
+ ProjectLogsManager.appId
76
+ }/logs/crm?serverlessFunction=${ProjectLogsManager.functionName}`
77
+ )
78
+ );
79
+ }
80
+ logger.log();
81
+ uiLine();
82
+ }
135
83
 
136
- exports.command = 'logs [--project] [--app] [--function] [--endpoint]';
84
+ exports.command = 'logs';
137
85
  exports.describe = uiBetaTag(i18n(`${i18nKey}.describe`), false);
138
86
 
139
87
  exports.handler = async options => {
140
- await loadAndValidateOptions(options);
141
-
142
88
  const accountId = getAccountId(options);
89
+ trackCommandUsage('project-logs', null, accountId);
143
90
 
144
- const {
145
- projectName: promptProjectName,
146
- appName: promptAppName,
147
- functionName: promptFunctionName,
148
- endpointName: promptEndpointName,
149
- } = await projectLogsPrompt(accountId, options);
150
-
151
- const projectName = options.project || promptProjectName;
152
- const appName = options.app || promptAppName;
153
- const functionName =
154
- options.function || promptFunctionName || options.endpoint;
155
- const endpointName = options.endpoint || promptEndpointName;
91
+ await loadAndValidateOptions(options);
156
92
 
157
- // let relativeAppPath;
158
- let appId;
93
+ try {
94
+ await ProjectLogsManager.init(accountId);
159
95
 
160
- if (appName && !endpointName) {
161
- await ensureProjectExists(accountId, projectName, {
162
- allowCreate: false,
96
+ const { functionName } = await projectLogsPrompt({
97
+ functionChoices: ProjectLogsManager.getFunctionNames(),
98
+ promptOptions: options,
99
+ projectName: ProjectLogsManager.projectName,
163
100
  });
164
101
 
165
- // const { deployedBuild, id: projectId } = await fetchProject(
166
- // accountId,
167
- // projectName
168
- // );
169
- const { id: projectId } = await fetchProject(accountId, projectName);
170
-
171
- const { results: deployComponents } = await fetchDeployComponentsMetadata(
172
- accountId,
173
- projectId
174
- );
175
-
176
- const appComponent = deployComponents.find(
177
- c => c.componentName === appName
178
- );
179
-
180
- if (appComponent) {
181
- appId = appComponent.componentIdentifier;
182
- }
183
-
184
- // if (deployedBuild && deployedBuild.subbuildStatuses) {
185
- // const appSubbuild = deployedBuild.subbuildStatuses.find(
186
- // subbuild => subbuild.buildName === appName
187
- // );
188
- // if (appSubbuild) {
189
- // relativeAppPath = appSubbuild.rootPath;
190
- // } else {
191
- // logger.error(
192
- // i18n(`${i18nKey}.errors.invalidAppName`, {
193
- // appName: options.app,
194
- // projectName,
195
- // })
196
- // );
197
- // process.exit(EXIT_CODES.ERROR);
198
- // }
199
- // }
200
- }
201
-
202
- trackCommandUsage('project-logs', null, accountId);
203
-
204
- const logsInfo = [accountId, `"${projectName}"`];
205
- let tableHeader;
102
+ ProjectLogsManager.setFunction(functionName);
206
103
 
207
- if (endpointName) {
208
- logsInfo.push(`"${endpointName}"`);
209
- tableHeader = getTableHeader([
210
- i18n(`${i18nKey}.table.accountHeader`),
211
- i18n(`${i18nKey}.table.projectHeader`),
212
- i18n(`${i18nKey}.table.endpointHeader`),
213
- ]);
214
- } else {
215
- logsInfo.push(`"${appName}"`);
216
- logsInfo.push(functionName);
217
- tableHeader = getTableHeader([
218
- i18n(`${i18nKey}.table.accountHeader`),
219
- i18n(`${i18nKey}.table.projectHeader`),
220
- i18n(`${i18nKey}.table.appHeader`),
221
- i18n(`${i18nKey}.table.functionHeader`),
222
- ]);
104
+ logPreamble();
105
+ } catch (e) {
106
+ logApiErrorInstance(e, {
107
+ accountId: getAccountId(),
108
+ projectName: ProjectLogsManager.projectName,
109
+ });
110
+ return process.exit(EXIT_CODES.ERROR);
223
111
  }
224
-
225
- logger.log(i18n(`${i18nKey}.logs.showingLogs`));
226
- logger.log(
227
- getTableContents([tableHeader, logsInfo], { border: { bodyLeft: ' ' } })
228
- );
229
-
230
- logger.log(
231
- appId
232
- ? uiLink(
233
- i18n(`${i18nKey}.logs.hubspotLogsDirectLink`),
234
- `${getPrivateAppsUrl(accountId)}/${appId}/logs/extensions`
235
- )
236
- : uiLink(
237
- i18n(`${i18nKey}.logs.hubspotLogsLink`),
238
- getPrivateAppsUrl(accountId)
239
- )
240
- );
241
- logger.log();
242
- uiLine();
243
-
244
- // const showFinalMessage = await handleFunctionLog(accountId, {
245
- // ...options,
246
- // projectName,
247
- // appPath: relativeAppPath,
248
- // functionName: functionName || endpointName,
249
- // });
250
-
251
- // if (showFinalMessage) {
252
- // uiLine();
253
- // }
254
112
  };
255
113
 
256
114
  exports.builder = yargs => {
@@ -262,22 +120,6 @@ exports.builder = yargs => {
262
120
  requiresArg: true,
263
121
  type: 'string',
264
122
  },
265
- endpoint: {
266
- alias: 'endpoint',
267
- describe: i18n(`${i18nKey}.options.endpoint.describe`),
268
- requiresArg: true,
269
- type: 'string',
270
- },
271
- app: {
272
- describe: i18n(`${i18nKey}.options.app.describe`),
273
- requiresArg: true,
274
- type: 'string',
275
- },
276
- project: {
277
- describe: i18n(`${i18nKey}.options.project.describe`),
278
- requiresArg: true,
279
- type: 'string',
280
- },
281
123
  latest: {
282
124
  alias: 'l',
283
125
  describe: i18n(`${i18nKey}.options.latest.describe`),
@@ -295,21 +137,17 @@ exports.builder = yargs => {
295
137
  limit: {
296
138
  describe: i18n(`${i18nKey}.options.limit.describe`),
297
139
  type: 'number',
298
- default: 10,
299
140
  },
300
141
  })
301
- .conflicts('tail', 'limit');
302
-
303
- yargs.example([['$0 project logs', i18n(`${i18nKey}.examples.default`)]]);
304
- yargs.example([
305
- [
306
- '$0 project logs --project=my-project --app=app --function=my-function',
307
- i18n(`${i18nKey}.examples.withOptions`),
308
- ],
309
- ]);
142
+ .conflicts('tail', 'limit')
143
+ .example([
144
+ ['$0 project logs', i18n(`${i18nKey}.examples.default`)],
145
+ [
146
+ '$0 project logs --function=my-function',
147
+ i18n(`${i18nKey}.examples.withOptions`),
148
+ ],
149
+ ]);
310
150
 
311
- addConfigOptions(yargs);
312
- addAccountOptions(yargs);
313
151
  addUseEnvironmentOptions(yargs);
314
152
 
315
153
  return yargs;
@@ -86,14 +86,12 @@ exports.handler = async options => {
86
86
  });
87
87
 
88
88
  let appName;
89
- let preventProjectMigrations;
90
- let listingInfo;
91
89
  try {
92
90
  const selectedApp = await fetchPublicAppMetadata(appId, accountId);
93
91
  // preventProjectMigrations returns true if we have not added app to allowlist config.
94
92
  // listingInfo will only exist for marketplace apps
95
- preventProjectMigrations = selectedApp.preventProjectMigrations;
96
- listingInfo = selectedApp.listingInfo;
93
+ const preventProjectMigrations = selectedApp.preventProjectMigrations;
94
+ const listingInfo = selectedApp.listingInfo;
97
95
  if (preventProjectMigrations && listingInfo) {
98
96
  logger.error(i18n(`${i18nKey}.errors.invalidApp`, { appId }));
99
97
  process.exit(EXIT_CODES.ERROR);
@@ -191,10 +189,9 @@ exports.handler = async options => {
191
189
  { includesRootDir: true, hideLogs: true }
192
190
  );
193
191
 
194
- const isListed = Boolean(listingInfo);
195
192
  trackCommandMetadataUsage(
196
193
  'migrate-app',
197
- { projectName, appId, status, preventProjectMigrations, isListed },
194
+ { type: projectName, assetType: appId, successful: status },
198
195
  accountId
199
196
  );
200
197
 
@@ -75,7 +75,7 @@ exports.handler = async options => {
75
75
  result.uploadError,
76
76
  new ApiErrorContext({
77
77
  accountId,
78
- projectName: projectConfig.name,
78
+ request: 'project upload',
79
79
  })
80
80
  );
81
81
  }
@@ -102,8 +102,10 @@ exports.handler = async options => {
102
102
  process.exit(EXIT_CODES.SUCCESS);
103
103
  }
104
104
  } catch (e) {
105
- const projectName = projectConfig.name;
106
- logApiErrorInstance(e, new ApiErrorContext({ accountId, projectName }));
105
+ logApiErrorInstance(
106
+ e,
107
+ new ApiErrorContext({ accountId, request: 'project upload' })
108
+ );
107
109
  process.exit(EXIT_CODES.ERROR);
108
110
  }
109
111
  };
@@ -71,10 +71,7 @@ const handleUserInput = (accountId, projectName, currentBuildId) => {
71
71
  ) {
72
72
  process.exit(EXIT_CODES.SUCCESS);
73
73
  } else {
74
- logApiErrorInstance(
75
- err,
76
- new ApiErrorContext({ accountId, projectName: projectName })
77
- );
74
+ logApiErrorInstance(err, new ApiErrorContext({ accountId }));
78
75
  process.exit(EXIT_CODES.ERROR);
79
76
  }
80
77
  }
@@ -146,7 +143,7 @@ exports.handler = async options => {
146
143
  result.uploadError,
147
144
  new ApiErrorContext({
148
145
  accountId,
149
- projectName: projectConfig.name,
146
+ request: 'project upload',
150
147
  })
151
148
  );
152
149
  }
@@ -156,10 +153,7 @@ exports.handler = async options => {
156
153
  await startWatching();
157
154
  }
158
155
  } catch (e) {
159
- logApiErrorInstance(
160
- e,
161
- new ApiErrorContext({ accountId, projectName: projectConfig.name })
162
- );
156
+ logApiErrorInstance(e, new ApiErrorContext({ accountId }));
163
157
  }
164
158
  };
165
159
 
@@ -13,6 +13,7 @@ const dev = require('./project/dev');
13
13
  const add = require('./project/add');
14
14
  const migrateApp = require('./project/migrateApp');
15
15
  const cloneApp = require('./project/cloneApp');
16
+ const installDeps = require('./project/installDeps');
16
17
 
17
18
  const i18nKey = 'commands.project';
18
19
 
@@ -36,6 +37,7 @@ exports.builder = yargs => {
36
37
  .command(open)
37
38
  .command(migrateApp)
38
39
  .command(cloneApp)
40
+ .command(installDeps)
39
41
  .demandCommand(1, '');
40
42
 
41
43
  return yargs;
@@ -145,6 +145,7 @@ exports.handler = async options => {
145
145
  });
146
146
 
147
147
  const sandboxAccountConfig = getAccountConfig(result.sandbox.sandboxHubId);
148
+ // For v1 sandboxes, keep sync here. Once we migrate to v2, this will be handled by BE automatically
148
149
  const handleSyncSandbox = async syncTasks => {
149
150
  await syncSandbox({
150
151
  accountConfig: sandboxAccountConfig,
@@ -3,7 +3,6 @@ const { i18n } = require('../lib/lang');
3
3
  const { uiBetaTag } = require('../lib/ui');
4
4
  const create = require('./sandbox/create');
5
5
  const del = require('./sandbox/delete');
6
- const sync = require('./sandbox/sync');
7
6
 
8
7
  const i18nKey = 'commands.sandbox';
9
8
 
@@ -17,7 +16,6 @@ exports.builder = yargs => {
17
16
  yargs
18
17
  .command(create)
19
18
  .command(del)
20
- .command(sync)
21
19
  .demandCommand(1, '');
22
20
 
23
21
  return yargs;