@hubspot/cli 4.1.8-beta.5 → 4.1.8-beta.6

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.
@@ -8,6 +8,7 @@ const {
8
8
  } = require('../../lib/commonOpts');
9
9
  const { loadAndValidateOptions } = require('../../lib/validation');
10
10
  const { i18n } = require('../../lib/lang');
11
+ const { getTableContents } = require('@hubspot/cli-lib/lib/table');
11
12
 
12
13
  const i18nKey = 'cli.commands.accounts.subcommands.info';
13
14
  exports.describe = i18n(`${i18nKey}.describe`);
@@ -26,11 +27,12 @@ exports.handler = async options => {
26
27
 
27
28
  const response = await getAccessToken(personalAccessKey, env, accountId);
28
29
 
29
- let scopeGroups = response.scopeGroups.join('\n');
30
+ const scopeGroups = response.scopeGroups.map(s => [s]);
30
31
 
31
32
  logger.log(i18n(`${i18nKey}.name`, { name }));
32
33
  logger.log(i18n(`${i18nKey}.accountId`, { accountId }));
33
- logger.log(i18n(`${i18nKey}.scopeGroups`, { scopeGroups }));
34
+ logger.log(i18n(`${i18nKey}.scopeGroups`));
35
+ logger.log(getTableContents(scopeGroups, { border: { bodyLeft: ' ' } }));
34
36
  } else {
35
37
  logger.log(i18n(`${i18nKey}.errors.notUsingPersonalAccessKey`));
36
38
  }
@@ -35,7 +35,7 @@ exports.handler = async options => {
35
35
  path.resolve(getCwd(), options.location || location),
36
36
  options.name || name,
37
37
  options.template || template,
38
- options.repoPath
38
+ options.templateSource
39
39
  );
40
40
 
41
41
  logger.log('');
@@ -62,8 +62,8 @@ exports.builder = yargs => {
62
62
  describe: i18n(`${i18nKey}.options.template.describe`),
63
63
  type: 'string',
64
64
  },
65
- repoPath: {
66
- describe: i18n(`${i18nKey}.options.repoPath.describe`),
65
+ templateSource: {
66
+ describe: i18n(`${i18nKey}.options.templateSource.describe`),
67
67
  type: 'string',
68
68
  },
69
69
  });
@@ -52,32 +52,30 @@ exports.handler = async options => {
52
52
 
53
53
  let buildIdToDeploy = buildIdOption;
54
54
 
55
- if (!buildIdOption) {
56
- const { latestBuild, deployedBuildId } = await fetchProject(
57
- accountId,
58
- projectName
59
- );
60
- if (!latestBuild || !latestBuild.buildId) {
61
- logger.error(i18n(`${i18nKey}.errors.noBuilds`));
62
- process.exit(EXIT_CODES.ERROR);
63
- }
64
- const buildIdPromptResponse = await buildIdPrompt(
65
- latestBuild.buildId,
66
- deployedBuildId,
67
- projectName
68
- );
69
-
70
- buildIdToDeploy = buildIdPromptResponse.buildId;
71
- }
55
+ try {
56
+ if (!buildIdOption) {
57
+ const { latestBuild, deployedBuildId } = await fetchProject(
58
+ accountId,
59
+ projectName
60
+ );
61
+ if (!latestBuild || !latestBuild.buildId) {
62
+ logger.error(i18n(`${i18nKey}.errors.noBuilds`));
63
+ process.exit(EXIT_CODES.ERROR);
64
+ }
65
+ const buildIdPromptResponse = await buildIdPrompt(
66
+ latestBuild.buildId,
67
+ deployedBuildId,
68
+ projectName
69
+ );
72
70
 
73
- if (!buildIdToDeploy) {
74
- logger.error(i18n(`${i18nKey}.errors.noBuildId`));
75
- process.exit(EXIT_CODES.ERROR);
76
- }
71
+ buildIdToDeploy = buildIdPromptResponse.buildId;
72
+ }
77
73
 
78
- let exitCode = EXIT_CODES.SUCCESS;
74
+ if (!buildIdToDeploy) {
75
+ logger.error(i18n(`${i18nKey}.errors.noBuildId`));
76
+ process.exit(EXIT_CODES.ERROR);
77
+ }
79
78
 
80
- try {
81
79
  const deployResp = await deployProject(
82
80
  accountId,
83
81
  projectName,
@@ -90,7 +88,6 @@ exports.handler = async options => {
90
88
  details: deployResp.error.message,
91
89
  })
92
90
  );
93
- exitCode = EXIT_CODES.ERROR;
94
91
  return;
95
92
  }
96
93
 
@@ -106,9 +103,8 @@ exports.handler = async options => {
106
103
  } else {
107
104
  logApiErrorInstance(e, new ApiErrorContext({ accountId, projectName }));
108
105
  }
109
- exitCode = 1;
106
+ process.exit(EXIT_CODES.ERROR);
110
107
  }
111
- process.exit(exitCode);
112
108
  };
113
109
 
114
110
  exports.builder = yargs => {
@@ -44,83 +44,77 @@ exports.handler = async options => {
44
44
 
45
45
  trackCommandUsage('project-download', null, accountId);
46
46
 
47
- const projectExists = await ensureProjectExists(accountId, projectName, {
48
- allowCreate: false,
49
- noLogs: true,
50
- });
51
-
52
- if (!projectExists) {
53
- logger.error(
54
- i18n(`${i18nKey}.errors.projectNotFound`, {
55
- projectName: chalk.bold(projectName),
56
- accountId: chalk.bold(accountId),
57
- })
58
- );
59
- let { name: promptedProjectName } = await downloadProjectPrompt(options);
60
- let projectName = promptedProjectName || project;
61
- }
47
+ try {
48
+ const projectExists = await ensureProjectExists(accountId, projectName, {
49
+ allowCreate: false,
50
+ noLogs: true,
51
+ });
52
+
53
+ if (!projectExists) {
54
+ logger.error(
55
+ i18n(`${i18nKey}.errors.projectNotFound`, {
56
+ projectName: chalk.bold(projectName),
57
+ accountId: chalk.bold(accountId),
58
+ })
59
+ );
60
+ let { name: promptedProjectName } = await downloadProjectPrompt(options);
61
+ let projectName = promptedProjectName || project;
62
+ }
62
63
 
63
- const absoluteDestPath = dest ? path.resolve(getCwd(), dest) : getCwd();
64
+ const absoluteDestPath = dest ? path.resolve(getCwd(), dest) : getCwd();
64
65
 
65
- const projectConfigCreated = await createProjectConfig(
66
- absoluteDestPath,
67
- projectName,
68
- { name: 'no-template' }
69
- );
66
+ const projectConfigCreated = await createProjectConfig(
67
+ absoluteDestPath,
68
+ projectName,
69
+ { name: 'no-template' }
70
+ );
70
71
 
71
- if (!projectConfigCreated) {
72
- logger.log(i18n(`${i18nKey}.logs.downloadCancelled`));
73
- process.exit(EXIT_CODES.SUCCESS);
74
- }
72
+ if (!projectConfigCreated) {
73
+ logger.log(i18n(`${i18nKey}.logs.downloadCancelled`));
74
+ process.exit(EXIT_CODES.SUCCESS);
75
+ }
75
76
 
76
- let success = false;
77
- let buildNumberToDownload = buildNumber;
77
+ let buildNumberToDownload = buildNumber;
78
78
 
79
- if (!buildNumberToDownload) {
80
- let projectBuildsResult;
79
+ if (!buildNumberToDownload) {
80
+ let projectBuildsResult;
81
81
 
82
- try {
83
82
  projectBuildsResult = await fetchProjectBuilds(accountId, projectName);
84
- } catch (e) {
85
- logApiErrorInstance(e, new ApiErrorContext({ accountId }));
86
- process.exit(EXIT_CODES.ERROR);
87
- }
88
83
 
89
- const { results: projectBuilds } = projectBuildsResult;
84
+ const { results: projectBuilds } = projectBuildsResult;
90
85
 
91
- if (projectBuilds && projectBuilds.length) {
92
- const latestBuild = projectBuilds[0];
93
- buildNumberToDownload = latestBuild.buildId;
86
+ if (projectBuilds && projectBuilds.length) {
87
+ const latestBuild = projectBuilds[0];
88
+ buildNumberToDownload = latestBuild.buildId;
89
+ }
94
90
  }
95
- }
96
91
 
97
- const zippedProject = await downloadProject(
98
- accountId,
99
- projectName,
100
- buildNumberToDownload
101
- );
102
-
103
- success = await extractZipArchive(
104
- zippedProject,
105
- projectName,
106
- path.resolve(absoluteDestPath, 'src'),
107
- {
108
- includesRootDir: false,
109
- }
110
- );
92
+ const zippedProject = await downloadProject(
93
+ accountId,
94
+ projectName,
95
+ buildNumberToDownload
96
+ );
97
+
98
+ await extractZipArchive(
99
+ zippedProject,
100
+ projectName,
101
+ path.resolve(absoluteDestPath, 'src'),
102
+ {
103
+ includesRootDir: false,
104
+ }
105
+ );
111
106
 
112
- if (!success) {
113
- logger.log(i18n(`${i18nKey}.errors.downloadFailed`));
107
+ logger.log(
108
+ i18n(`${i18nKey}.logs.downloadSucceeded`, {
109
+ buildId: buildNumberToDownload,
110
+ projectName,
111
+ })
112
+ );
113
+ process.exit(EXIT_CODES.SUCCESS);
114
+ } catch (e) {
115
+ logApiErrorInstance(e, new ApiErrorContext({ accountId, projectName }));
114
116
  process.exit(EXIT_CODES.ERROR);
115
117
  }
116
-
117
- logger.log(
118
- i18n(`${i18nKey}.logs.downloadSucceeded`, {
119
- buildId: buildNumberToDownload,
120
- projectName,
121
- })
122
- );
123
- process.exit(EXIT_CODES.SUCCESS);
124
118
  };
125
119
 
126
120
  exports.builder = yargs => {
@@ -127,7 +127,10 @@ exports.handler = async options => {
127
127
  if (e.statusCode === 404) {
128
128
  logger.error(`Project ${projectConfig.name} not found. `);
129
129
  } else {
130
- logApiErrorInstance(e, new ApiErrorContext({ accountId }));
130
+ logApiErrorInstance(
131
+ e,
132
+ new ApiErrorContext({ accountId, projectName: projectConfig.name })
133
+ );
131
134
  }
132
135
  }
133
136
  };
@@ -22,6 +22,10 @@ const {
22
22
  getProjectAppFunctionLogs,
23
23
  getLatestProjectAppFunctionLog,
24
24
  } = require('@hubspot/cli-lib/api/functions');
25
+ const {
26
+ logApiErrorInstance,
27
+ ApiErrorContext,
28
+ } = require('@hubspot/cli-lib/errorHandlers');
25
29
  const {
26
30
  getFunctionLogs,
27
31
  getLatestFunctionLog,
@@ -44,10 +48,16 @@ const getPrivateAppsUrl = accountId => {
44
48
  return `${baseUrl}/private-apps/${accountId}`;
45
49
  };
46
50
 
47
- const handleLogsError = (e, name) => {
48
- logger.debug(`Log fetch error: ${e.message}`);
51
+ const handleLogsError = (e, name, projectName) => {
49
52
  if (e.statusCode === 404) {
53
+ logger.debug(`Log fetch error: ${e.message}`);
50
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);
51
61
  }
52
62
  };
53
63
 
@@ -77,7 +87,7 @@ const handleFunctionLog = async (accountId, options) => {
77
87
  )
78
88
  : getFunctionLogs(accountId, functionName, { after });
79
89
  } catch (e) {
80
- handleLogsError(e, functionName);
90
+ handleLogsError(e, functionName, projectName);
81
91
  }
82
92
  };
83
93
 
@@ -89,7 +99,7 @@ const handleFunctionLog = async (accountId, options) => {
89
99
  projectName,
90
100
  appPath
91
101
  )
92
- : getLatestFunctionLog(accountId, functionName);
102
+ : getLatestFunctionLog(accountId, functionName, projectName);
93
103
  };
94
104
 
95
105
  if (follow) {
@@ -104,14 +114,14 @@ const handleFunctionLog = async (accountId, options) => {
104
114
  try {
105
115
  logsResp = await fetchLatest();
106
116
  } catch (e) {
107
- handleLogsError(e, functionName);
117
+ handleLogsError(e, functionName, projectName);
108
118
  return true;
109
119
  }
110
120
  } else {
111
121
  try {
112
122
  logsResp = await tailCall();
113
123
  } catch (e) {
114
- handleLogsError(e, functionName);
124
+ handleLogsError(e, functionName, projectName);
115
125
  return true;
116
126
  }
117
127
  }
@@ -50,54 +50,53 @@ exports.handler = async options => {
50
50
 
51
51
  await ensureProjectExists(accountId, projectConfig.name, { forceCreate });
52
52
 
53
- const result = await handleProjectUpload(
54
- accountId,
55
- projectConfig,
56
- projectDir,
57
- pollProjectBuildAndDeploy,
58
- message
59
- );
60
-
61
- if (result.error) {
62
- if (
63
- isSpecifiedError(result.error, {
64
- subCategory: ERROR_TYPES.PROJECT_LOCKED,
65
- })
66
- ) {
67
- logger.log();
68
- logger.error(i18n(`${i18nKey}.errors.projectLockedError`));
69
- logger.log();
70
- } else {
71
- logApiErrorInstance(
72
- result.error,
73
- new ApiErrorContext({
74
- accountId,
75
- projectName: projectConfig.name,
53
+ try {
54
+ const result = await handleProjectUpload(
55
+ accountId,
56
+ projectConfig,
57
+ projectDir,
58
+ pollProjectBuildAndDeploy,
59
+ message
60
+ );
61
+
62
+ if (result.error) {
63
+ if (
64
+ isSpecifiedError(result.error, {
65
+ subCategory: ERROR_TYPES.PROJECT_LOCKED,
76
66
  })
67
+ ) {
68
+ logger.log();
69
+ logger.error(i18n(`${i18nKey}.errors.projectLockedError`));
70
+ logger.log();
71
+ } else {
72
+ logApiErrorInstance(
73
+ result.error,
74
+ new ApiErrorContext({
75
+ accountId,
76
+ projectName: projectConfig.name,
77
+ })
78
+ );
79
+ }
80
+ process.exit(EXIT_CODES.ERROR);
81
+ }
82
+ if (result.buildSucceeded && !result.autodeployEnabled) {
83
+ uiLine();
84
+ logger.log(
85
+ chalk.bold(
86
+ i18n(`${i18nKey}.logs.buildSucceeded`, {
87
+ buildId: result.buildId,
88
+ })
89
+ )
77
90
  );
91
+ uiLine();
92
+ logFeedbackMessage(result.buildId);
93
+ process.exit(EXIT_CODES.SUCCESS);
78
94
  }
95
+ } catch (e) {
96
+ const projectName = projectConfig.name;
97
+ logApiErrorInstance(e, new ApiErrorContext({ accountId, projectName }));
79
98
  process.exit(EXIT_CODES.ERROR);
80
99
  }
81
- if (result.buildSucceeded && !result.autodeployEnabled) {
82
- uiLine();
83
- logger.log(
84
- chalk.bold(
85
- i18n(`${i18nKey}.logs.buildSucceeded`, {
86
- buildId: result.buildId,
87
- })
88
- )
89
- );
90
- logger.log(i18n(`${i18nKey}.logs.readyToGoLive`));
91
- logger.log(
92
- i18n(`${i18nKey}.logs.runCommand`, {
93
- command: chalk.hex('f5c26b')('hs project deploy'),
94
- })
95
- );
96
- uiLine();
97
- }
98
-
99
- logFeedbackMessage(result.buildId);
100
- process.exit(result.succeeded ? EXIT_CODES.SUCCESS : EXIT_CODES.ERROR);
101
100
  };
102
101
 
103
102
  exports.builder = yargs => {
@@ -99,33 +99,40 @@ exports.handler = async options => {
99
99
 
100
100
  await ensureProjectExists(accountId, projectConfig.name);
101
101
 
102
- const { results: builds } = await fetchProjectBuilds(
103
- accountId,
104
- projectConfig.name,
105
- options
106
- );
107
- const hasNoBuilds = !builds || !builds.length;
108
-
109
- const startWatching = async () => {
110
- await createWatcher(
102
+ try {
103
+ const { results: builds } = await fetchProjectBuilds(
111
104
  accountId,
112
- projectConfig,
113
- projectDir,
114
- handleBuildStatus,
115
- handleUserInput
105
+ projectConfig.name,
106
+ options
116
107
  );
117
- };
118
-
119
- // Upload all files if no build exists for this project yet
120
- if (initialUpload || hasNoBuilds) {
121
- await handleProjectUpload(
122
- accountId,
123
- projectConfig,
124
- projectDir,
125
- startWatching
108
+ const hasNoBuilds = !builds || !builds.length;
109
+
110
+ const startWatching = async () => {
111
+ await createWatcher(
112
+ accountId,
113
+ projectConfig,
114
+ projectDir,
115
+ handleBuildStatus,
116
+ handleUserInput
117
+ );
118
+ };
119
+
120
+ // Upload all files if no build exists for this project yet
121
+ if (initialUpload || hasNoBuilds) {
122
+ await handleProjectUpload(
123
+ accountId,
124
+ projectConfig,
125
+ projectDir,
126
+ startWatching
127
+ );
128
+ } else {
129
+ await startWatching();
130
+ }
131
+ } catch (e) {
132
+ logApiErrorInstance(
133
+ e,
134
+ new ApiErrorContext({ accountId, projectName: projectConfig.name })
126
135
  );
127
- } else {
128
- await startWatching();
129
136
  }
130
137
  };
131
138
 
@@ -186,12 +186,14 @@ exports.handler = async options => {
186
186
  throw err;
187
187
  }
188
188
 
189
- uiFeatureHighlight([
190
- 'accountsUseCommand',
191
- sandboxType === DEVELOPER_SANDBOX
192
- ? 'projectDevCommand'
193
- : 'projectUploadCommand',
194
- ]);
189
+ const highlightItems = ['accountsUseCommand', 'projectCreateCommand'];
190
+ if (sandboxType === DEVELOPER_SANDBOX) {
191
+ highlightItems.push('projectDevCommand');
192
+ } else {
193
+ highlightItems.push('projectUploadCommand');
194
+ }
195
+
196
+ uiFeatureHighlight(highlightItems);
195
197
  process.exit(EXIT_CODES.SUCCESS);
196
198
  } catch (error) {
197
199
  trackCommandUsage('sandbox-create', { successful: false }, accountId);
@@ -24,6 +24,12 @@ const {
24
24
  } = require('../../lib/sandboxes');
25
25
  const { syncSandbox } = require('../../lib/sandbox-sync');
26
26
  const { getValidEnv } = require('@hubspot/cli-lib/lib/environment');
27
+ const {
28
+ isSpecifiedError,
29
+ } = require('@hubspot/cli-lib/errorHandlers/apiErrors');
30
+ const {
31
+ logErrorInstance,
32
+ } = require('@hubspot/cli-lib/errorHandlers/standardErrors');
27
33
 
28
34
  const i18nKey = 'cli.commands.sandbox.subcommands.sync';
29
35
 
@@ -70,6 +76,32 @@ exports.handler = async options => {
70
76
  const isStandardSandbox =
71
77
  sandboxTypeMap[accountConfig.sandboxAccountType] === STANDARD_SANDBOX;
72
78
 
79
+ let availableSyncTasks;
80
+ try {
81
+ availableSyncTasks = await getAvailableSyncTypes(
82
+ parentAccountConfig,
83
+ accountConfig
84
+ );
85
+ } catch (error) {
86
+ if (
87
+ isSpecifiedError(error, {
88
+ statusCode: 404,
89
+ category: 'OBJECT_NOT_FOUND',
90
+ subCategory: 'SandboxErrors.SANDBOX_NOT_FOUND',
91
+ })
92
+ ) {
93
+ logger.error(
94
+ i18n('cli.lib.sandbox.sync.failure.objectNotFound', {
95
+ account: getAccountName(accountConfig),
96
+ })
97
+ );
98
+ } else {
99
+ logErrorInstance(error);
100
+ }
101
+ trackCommandUsage('sandbox-sync', { successful: false }, accountId);
102
+ process.exit(EXIT_CODES.ERROR);
103
+ }
104
+
73
105
  if (isDevelopmentSandbox) {
74
106
  logger.log(i18n(`${i18nKey}.info.developmentSandbox`));
75
107
  logger.log(
@@ -145,10 +177,6 @@ exports.handler = async options => {
145
177
  }
146
178
 
147
179
  try {
148
- const availableSyncTasks = await getAvailableSyncTypes(
149
- parentAccountConfig,
150
- accountConfig
151
- );
152
180
  const syncTasks = await getSyncTypesWithContactRecordsPrompt(
153
181
  accountConfig,
154
182
  availableSyncTasks,