@hubspot/cli 4.0.0 → 4.0.1-beta.2

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/bin/cli.js CHANGED
@@ -103,7 +103,7 @@ const performChecks = argv => {
103
103
  };
104
104
 
105
105
  const argv = yargs
106
- .usage('Tools for working with HubSpot')
106
+ .usage('The command line interface to interact with HubSpot.')
107
107
  .middleware([setLogLevel])
108
108
  .exitProcess(false)
109
109
  .fail(handleFailure)
@@ -0,0 +1,53 @@
1
+ const { logger } = require('@hubspot/cli-lib/logger');
2
+ const { getAccountConfig } = require('@hubspot/cli-lib/lib/config');
3
+ const { getAccessToken } = require('@hubspot/cli-lib/personalAccessKey.js');
4
+ const {
5
+ getAccountId,
6
+ addAccountOptions,
7
+ addConfigOptions,
8
+ } = require('../../lib/commonOpts');
9
+ const { loadAndValidateOptions } = require('../../lib/validation');
10
+ const { i18n } = require('@hubspot/cli-lib/lib/lang');
11
+
12
+ const i18nKey = 'cli.commands.accounts.subcommands.info';
13
+ exports.describe = i18n(`${i18nKey}.describe`);
14
+
15
+ exports.command = 'info [--account]';
16
+
17
+ exports.handler = async options => {
18
+ await loadAndValidateOptions(options);
19
+
20
+ let accountId = getAccountId(options);
21
+ const config = getAccountConfig(accountId);
22
+
23
+ // check if the provided account is using a personal access key, if not, show an error
24
+ if (config.authType === 'personalaccesskey') {
25
+ const { name, personalAccessKey, env } = config;
26
+
27
+ const response = await getAccessToken(personalAccessKey, env, accountId);
28
+
29
+ let scopeGroups = response.scopeGroups.join('\n');
30
+
31
+ logger.log(i18n(`${i18nKey}.name`, { name }));
32
+ logger.log(i18n(`${i18nKey}.accountId`, { accountId }));
33
+ logger.log(i18n(`${i18nKey}.scopeGroups`, { scopeGroups }));
34
+ } else {
35
+ logger.log(i18n(`${i18nKey}.errors.notUsingPersonalAccessKey`));
36
+ }
37
+ };
38
+
39
+ exports.builder = yargs => {
40
+ addConfigOptions(yargs, true);
41
+ addAccountOptions(yargs, true);
42
+
43
+ yargs.example([
44
+ ['$0 accounts info', i18n(`${i18nKey}.examples.default`)],
45
+ [
46
+ '$0 accounts info --account=MyAccount',
47
+ i18n(`${i18nKey}.examples.nameBased`),
48
+ ],
49
+ ['$0 accounts info --account=1234567', i18n(`${i18nKey}.examples.idBased`)],
50
+ ]);
51
+
52
+ return yargs;
53
+ };
@@ -19,6 +19,54 @@ const i18nKey = 'cli.commands.accounts.subcommands.list';
19
19
  exports.command = 'list';
20
20
  exports.describe = i18n(`${i18nKey}.describe`);
21
21
 
22
+ const sortAndMapPortals = portals => {
23
+ const mappedPortalData = {};
24
+ portals
25
+ .sort((a, b) => {
26
+ if (a.sandboxAccountType === null && b.sandboxAccountType !== null) {
27
+ return -1;
28
+ }
29
+ if (a.sandboxAccountType !== null && b.sandboxAccountType === null) {
30
+ return 1;
31
+ }
32
+ return 0;
33
+ })
34
+ .forEach(portal => {
35
+ if (
36
+ portal.sandboxAccountType !== undefined &&
37
+ portal.sandboxAccountType === null
38
+ ) {
39
+ mappedPortalData[portal.portalId] = [portal];
40
+ } else if (portal.sandboxAccountType && portal.parentAccountId) {
41
+ mappedPortalData[portal.parentAccountId] = [
42
+ ...(mappedPortalData[portal.parentAccountId] || []),
43
+ portal,
44
+ ];
45
+ } else {
46
+ mappedPortalData[portal.portalId] = [portal];
47
+ }
48
+ });
49
+ return mappedPortalData;
50
+ };
51
+
52
+ const getPortalData = mappedPortalData => {
53
+ const portalData = [];
54
+ Object.values(mappedPortalData).forEach(set => {
55
+ set.forEach((portal, i) => {
56
+ if (i === 0) {
57
+ portalData.push([portal.name, portal.portalId, portal.authType]);
58
+ } else {
59
+ portalData.push([
60
+ `↳ ${portal.name} [sandbox]`,
61
+ portal.portalId,
62
+ portal.authType,
63
+ ]);
64
+ }
65
+ });
66
+ });
67
+ return portalData;
68
+ };
69
+
22
70
  exports.handler = async options => {
23
71
  await loadAndValidateOptions(options);
24
72
 
@@ -28,9 +76,8 @@ exports.handler = async options => {
28
76
 
29
77
  const config = getConfig();
30
78
  const configPath = getConfigPath();
31
- const portalData = config.portals.map(portal => {
32
- return [portal.name, portal.portalId, portal.authType];
33
- });
79
+ const mappedPortalData = sortAndMapPortals(config.portals);
80
+ const portalData = getPortalData(mappedPortalData);
34
81
  portalData.unshift(
35
82
  getTableHeader([
36
83
  i18n(`${i18nKey}.labels.name`),
@@ -3,6 +3,7 @@ const { i18n } = require('@hubspot/cli-lib/lib/lang');
3
3
  const list = require('./accounts/list');
4
4
  const rename = require('./accounts/rename');
5
5
  const use = require('./accounts/use');
6
+ const info = require('./accounts/info');
6
7
 
7
8
  const i18nKey = 'cli.commands.accounts';
8
9
 
@@ -20,6 +21,7 @@ exports.builder = yargs => {
20
21
  })
21
22
  .command(rename)
22
23
  .command(use)
24
+ .command(info)
23
25
  .demandCommand(1, '');
24
26
 
25
27
  return yargs;
package/commands/auth.js CHANGED
@@ -13,8 +13,8 @@ const {
13
13
  } = require('@hubspot/cli-lib/personalAccessKey');
14
14
  const {
15
15
  updateAccountConfig,
16
- accountNameExistsInConfig,
17
16
  writeConfig,
17
+ getConfig,
18
18
  getConfigPath,
19
19
  } = require('@hubspot/cli-lib/lib/config');
20
20
  const { commaSeparatedValues } = require('@hubspot/cli-lib/lib/text');
@@ -23,8 +23,13 @@ const {
23
23
  personalAccessKeyPrompt,
24
24
  OAUTH_FLOW,
25
25
  API_KEY_FLOW,
26
- ACCOUNT_NAME,
27
26
  } = require('../lib/prompts/personalAccessKeyPrompt');
27
+ const {
28
+ enterAccountNamePrompt,
29
+ } = require('../lib/prompts/enterAccountNamePrompt');
30
+ const {
31
+ setAsDefaultAccountPrompt,
32
+ } = require('../lib/prompts/setAsDefaultAccountPrompt');
28
33
  const {
29
34
  addConfigOptions,
30
35
  setLogLevel,
@@ -34,6 +39,7 @@ const { logDebugInfo } = require('../lib/debugInfo');
34
39
  const { trackCommandUsage } = require('../lib/usageTracking');
35
40
  const { authenticateWithOauth } = require('../lib/oauth');
36
41
  const { EXIT_CODES } = require('../lib/enums/exitCodes');
42
+ const { uiFeatureHighlight } = require('../lib/ui');
37
43
 
38
44
  const i18nKey = 'cli.commands.auth';
39
45
 
@@ -45,34 +51,13 @@ const SUPPORTED_AUTHENTICATION_PROTOCOLS_TEXT = commaSeparatedValues(
45
51
  ALLOWED_AUTH_METHODS
46
52
  );
47
53
 
48
- const promptForAccountNameIfNotSet = async updatedConfig => {
49
- if (!updatedConfig.name) {
50
- let promptAnswer;
51
- let validName = null;
52
- while (!validName) {
53
- promptAnswer = await promptUser([ACCOUNT_NAME]);
54
-
55
- if (!accountNameExistsInConfig(promptAnswer.name)) {
56
- validName = promptAnswer.name;
57
- } else {
58
- logger.log(
59
- i18n(`${i18nKey}.errors.accountNameExists`, {
60
- name: promptAnswer.name,
61
- })
62
- );
63
- }
64
- }
65
- return validName;
66
- }
67
- };
68
-
69
- exports.command = 'auth [type]';
54
+ exports.command = 'auth [type] [--account]';
70
55
  exports.describe = i18n(`${i18nKey}.describe`, {
71
56
  supportedProtocols: SUPPORTED_AUTHENTICATION_PROTOCOLS_TEXT,
72
57
  });
73
58
 
74
59
  exports.handler = async options => {
75
- const { type, config: configPath, qa } = options;
60
+ const { type, config: configPath, qa, account } = options;
76
61
  const authType =
77
62
  (type && type.toLowerCase()) || PERSONAL_ACCESS_KEY_AUTH_METHOD.value;
78
63
  setLogLevel(options);
@@ -92,11 +77,18 @@ exports.handler = async options => {
92
77
  let configData;
93
78
  let updatedConfig;
94
79
  let validName;
80
+ let successAuthMethod;
81
+
95
82
  switch (authType) {
96
83
  case API_KEY_AUTH_METHOD.value:
97
84
  configData = await promptUser(API_KEY_FLOW);
98
85
  updatedConfig = await updateAccountConfig(configData);
99
- validName = await promptForAccountNameIfNotSet(updatedConfig);
86
+ validName = updatedConfig.name;
87
+
88
+ if (!validName) {
89
+ const { name: namePrompt } = await enterAccountNamePrompt();
90
+ validName = namePrompt;
91
+ }
100
92
 
101
93
  updateAccountConfig({
102
94
  ...updatedConfig,
@@ -105,13 +97,7 @@ exports.handler = async options => {
105
97
  });
106
98
  writeConfig();
107
99
 
108
- logger.success(
109
- i18n(`${i18nKey}.success.configFileUpdated`, {
110
- configFilename: DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME,
111
- authMethod: API_KEY_AUTH_METHOD.name,
112
- })
113
- );
114
-
100
+ successAuthMethod = API_KEY_AUTH_METHOD.name;
115
101
  break;
116
102
  case OAUTH_AUTH_METHOD.value:
117
103
  configData = await promptUser(OAUTH_FLOW);
@@ -119,16 +105,22 @@ exports.handler = async options => {
119
105
  ...configData,
120
106
  env,
121
107
  });
108
+ successAuthMethod = OAUTH_AUTH_METHOD.name;
122
109
  break;
123
110
  case PERSONAL_ACCESS_KEY_AUTH_METHOD.value:
124
- configData = await personalAccessKeyPrompt({ env });
111
+ configData = await personalAccessKeyPrompt({ env, account });
125
112
  updatedConfig = await updateConfigWithPersonalAccessKey(configData);
126
113
 
127
114
  if (!updatedConfig) {
128
- process.exit(EXIT_CODES.SUCCESS);
115
+ break;
129
116
  }
130
117
 
131
- validName = await promptForAccountNameIfNotSet(updatedConfig);
118
+ validName = updatedConfig.name;
119
+
120
+ if (!validName) {
121
+ const { name: namePrompt } = await enterAccountNamePrompt();
122
+ validName = namePrompt;
123
+ }
132
124
 
133
125
  updateAccountConfig({
134
126
  ...updatedConfig,
@@ -138,12 +130,7 @@ exports.handler = async options => {
138
130
  });
139
131
  writeConfig();
140
132
 
141
- logger.success(
142
- i18n(`${i18nKey}.success.configFileUpdated`, {
143
- configFilename: DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME,
144
- authMethod: PERSONAL_ACCESS_KEY_AUTH_METHOD.name,
145
- })
146
- );
133
+ successAuthMethod = PERSONAL_ACCESS_KEY_AUTH_METHOD.name;
147
134
  break;
148
135
  default:
149
136
  logger.error(
@@ -154,6 +141,43 @@ exports.handler = async options => {
154
141
  );
155
142
  break;
156
143
  }
144
+
145
+ if (!successAuthMethod) {
146
+ process.exit(EXIT_CODES.ERROR);
147
+ }
148
+
149
+ const accountName = updatedConfig.name || validName;
150
+
151
+ const setAsDefault = await setAsDefaultAccountPrompt(accountName);
152
+
153
+ logger.log('');
154
+ if (setAsDefault) {
155
+ logger.success(
156
+ i18n(`cli.lib.prompts.setAsDefaultAccountPrompt.setAsDefaultAccount`, {
157
+ accountName,
158
+ })
159
+ );
160
+ } else {
161
+ const config = getConfig();
162
+ logger.info(
163
+ i18n(`cli.lib.prompts.setAsDefaultAccountPrompt.keepingCurrentDefault`, {
164
+ accountName: config.defaultPortal,
165
+ })
166
+ );
167
+ }
168
+ logger.success(
169
+ i18n(`${i18nKey}.success.configFileUpdated`, {
170
+ configFilename: DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME,
171
+ authType: successAuthMethod,
172
+ accountName,
173
+ })
174
+ );
175
+ uiFeatureHighlight([
176
+ 'accountsUseCommand',
177
+ 'accountOption',
178
+ 'accountsListCommand',
179
+ ]);
180
+
157
181
  process.exit(EXIT_CODES.SUCCESS);
158
182
  };
159
183
 
@@ -172,6 +196,13 @@ exports.builder = yargs => {
172
196
  }),
173
197
  });
174
198
 
199
+ yargs.options({
200
+ account: {
201
+ describe: i18n(`${i18nKey}.options.account.describe`),
202
+ type: 'string',
203
+ },
204
+ });
205
+
175
206
  addConfigOptions(yargs, true);
176
207
  addTestingOptions(yargs, true);
177
208
 
@@ -35,7 +35,7 @@ exports.handler = async options => {
35
35
  trackCommandUsage('filemanager-fetch', {}, accountId);
36
36
 
37
37
  // Fetch and write file/folder.
38
- downloadFileOrFolder(accountId, src, dest, options);
38
+ await downloadFileOrFolder(accountId, src, dest, options);
39
39
  };
40
40
 
41
41
  exports.builder = yargs => {
package/commands/init.js CHANGED
@@ -30,12 +30,15 @@ const { promptUser } = require('../lib/prompts/promptUtils');
30
30
  const {
31
31
  OAUTH_FLOW,
32
32
  API_KEY_FLOW,
33
- ACCOUNT_NAME,
34
33
  personalAccessKeyPrompt,
35
34
  } = require('../lib/prompts/personalAccessKeyPrompt');
35
+ const {
36
+ enterAccountNamePrompt,
37
+ } = require('../lib/prompts/enterAccountNamePrompt');
36
38
  const { logDebugInfo } = require('../lib/debugInfo');
37
39
  const { authenticateWithOauth } = require('../lib/oauth');
38
40
  const { EXIT_CODES } = require('../lib/enums/exitCodes');
41
+ const { uiFeatureHighlight } = require('../lib/ui');
39
42
 
40
43
  const i18nKey = 'cli.commands.init';
41
44
 
@@ -45,9 +48,9 @@ const TRACKING_STATUS = {
45
48
  COMPLETE: 'complete',
46
49
  };
47
50
 
48
- const personalAccessKeyConfigCreationFlow = async env => {
49
- const configData = await personalAccessKeyPrompt({ env });
50
- const { name } = await promptUser([ACCOUNT_NAME]);
51
+ const personalAccessKeyConfigCreationFlow = async (env, account) => {
52
+ const configData = await personalAccessKeyPrompt({ env, account });
53
+ const { name } = await enterAccountNamePrompt();
51
54
  const accountConfig = {
52
55
  ...configData,
53
56
  name,
@@ -85,13 +88,23 @@ const CONFIG_CREATION_FLOWS = {
85
88
  [API_KEY_AUTH_METHOD.value]: apiKeyConfigCreationFlow,
86
89
  };
87
90
 
88
- exports.command = 'init';
91
+ const AUTH_TYPE_NAMES = {
92
+ [PERSONAL_ACCESS_KEY_AUTH_METHOD.value]: PERSONAL_ACCESS_KEY_AUTH_METHOD.name,
93
+ [OAUTH_AUTH_METHOD.value]: OAUTH_AUTH_METHOD.name,
94
+ [API_KEY_AUTH_METHOD.value]: API_KEY_AUTH_METHOD.name,
95
+ };
96
+
97
+ exports.command = 'init [--account]';
89
98
  exports.describe = i18n(`${i18nKey}.describe`, {
90
99
  configName: DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME,
91
100
  });
92
101
 
93
102
  exports.handler = async options => {
94
- const { auth: authType = PERSONAL_ACCESS_KEY_AUTH_METHOD.value, c } = options;
103
+ const {
104
+ auth: authType = PERSONAL_ACCESS_KEY_AUTH_METHOD.value,
105
+ c,
106
+ account: optionalAccount,
107
+ } = options;
95
108
  const configPath = (c && path.join(getCwd(), c)) || getConfigPath();
96
109
  setLogLevel(options);
97
110
  logDebugInfo(options);
@@ -106,7 +119,7 @@ exports.handler = async options => {
106
119
  configPath,
107
120
  })
108
121
  );
109
- logger.info(i18n(`${i18nKey}.info.updateConfig`));
122
+ logger.info(i18n(`${i18nKey}.logs.updateConfig`));
110
123
  process.exit(EXIT_CODES.ERROR);
111
124
  }
112
125
 
@@ -115,16 +128,25 @@ exports.handler = async options => {
115
128
  handleExit(deleteEmptyConfigFile);
116
129
 
117
130
  try {
118
- const { accountId, name } = await CONFIG_CREATION_FLOWS[authType](env);
131
+ const { accountId, name } = await CONFIG_CREATION_FLOWS[authType](
132
+ env,
133
+ optionalAccount
134
+ );
119
135
  const configPath = getConfigPath();
120
136
 
137
+ logger.log('');
121
138
  logger.success(
122
139
  i18n(`${i18nKey}.success.configFileCreated`, {
123
140
  configPath,
124
- authType,
141
+ })
142
+ );
143
+ logger.success(
144
+ i18n(`${i18nKey}.success.configFileUpdated`, {
145
+ authType: AUTH_TYPE_NAMES[authType],
125
146
  account: name || accountId,
126
147
  })
127
148
  );
149
+ uiFeatureHighlight(['helpCommand', 'authCommand', 'accountsListCommand']);
128
150
 
129
151
  trackAuthAction('init', authType, TRACKING_STATUS.COMPLETE, accountId);
130
152
  process.exit(EXIT_CODES.SUCCESS);
@@ -135,18 +157,24 @@ exports.handler = async options => {
135
157
  };
136
158
 
137
159
  exports.builder = yargs => {
138
- yargs.option('auth', {
139
- describe: i18n(`${i18nKey}.options.auth.describe`),
140
- type: 'string',
141
- choices: [
142
- `${PERSONAL_ACCESS_KEY_AUTH_METHOD.value}`,
143
- `${OAUTH_AUTH_METHOD.value}`,
144
- `${API_KEY_AUTH_METHOD.value}`,
145
- ],
146
- default: PERSONAL_ACCESS_KEY_AUTH_METHOD.value,
147
- defaultDescription: i18n(`${i18nKey}.options.auth.defaultDescription`, {
148
- defaultType: PERSONAL_ACCESS_KEY_AUTH_METHOD.value,
149
- }),
160
+ yargs.options({
161
+ auth: {
162
+ describe: i18n(`${i18nKey}.options.auth.describe`),
163
+ type: 'string',
164
+ choices: [
165
+ `${PERSONAL_ACCESS_KEY_AUTH_METHOD.value}`,
166
+ `${OAUTH_AUTH_METHOD.value}`,
167
+ `${API_KEY_AUTH_METHOD.value}`,
168
+ ],
169
+ default: PERSONAL_ACCESS_KEY_AUTH_METHOD.value,
170
+ defaultDescription: i18n(`${i18nKey}.options.auth.defaultDescription`, {
171
+ defaultType: PERSONAL_ACCESS_KEY_AUTH_METHOD.value,
172
+ }),
173
+ },
174
+ account: {
175
+ describe: i18n(`${i18nKey}.options.account.describe`),
176
+ type: 'string',
177
+ },
150
178
  });
151
179
 
152
180
  addConfigOptions(yargs, true);
@@ -8,14 +8,14 @@ const { trackCommandUsage } = require('../../lib/usageTracking');
8
8
  const { loadAndValidateOptions } = require('../../lib/validation');
9
9
  const { getCwd } = require('@hubspot/cli-lib/path');
10
10
  const path = require('path');
11
+ const chalk = require('chalk');
11
12
  const {
12
13
  createProjectPrompt,
13
14
  } = require('../../lib/prompts/createProjectPrompt');
14
- const {
15
- createProjectConfig,
16
- showProjectWelcomeMessage,
17
- } = require('../../lib/projects');
15
+ const { createProjectConfig } = require('../../lib/projects');
18
16
  const { i18n } = require('@hubspot/cli-lib/lib/lang');
17
+ const { uiFeatureHighlight } = require('../../lib/ui');
18
+ const { logger } = require('@hubspot/cli-lib/logger');
19
19
 
20
20
  const i18nKey = 'cli.commands.project.subcommands.create';
21
21
 
@@ -37,7 +37,14 @@ exports.handler = async options => {
37
37
  options.template || template
38
38
  );
39
39
 
40
- showProjectWelcomeMessage();
40
+ logger.log('');
41
+ logger.log(chalk.bold(i18n(`${i18nKey}.logs.welcomeMessage`)));
42
+ uiFeatureHighlight([
43
+ 'createCommand',
44
+ 'projectUploadCommand',
45
+ 'projectDeployCommand',
46
+ 'projectHelpCommand',
47
+ ]);
41
48
  };
42
49
 
43
50
  exports.builder = yargs => {
@@ -12,41 +12,44 @@ const {
12
12
  const { logger } = require('@hubspot/cli-lib/logger');
13
13
  const { deployProject, fetchProject } = require('@hubspot/cli-lib/api/dfs');
14
14
  const { loadAndValidateOptions } = require('../../lib/validation');
15
- const {
16
- getProjectConfig,
17
- pollDeployStatus,
18
- validateProjectConfig,
19
- } = require('../../lib/projects');
15
+ const { getProjectConfig, pollDeployStatus } = require('../../lib/projects');
16
+ const { projectNamePrompt } = require('../../lib/prompts/projectNamePrompt');
20
17
  const { i18n } = require('@hubspot/cli-lib/lib/lang');
21
18
 
22
19
  const i18nKey = 'cli.commands.project.subcommands.deploy';
23
20
  const { EXIT_CODES } = require('../../lib/enums/exitCodes');
24
21
 
25
- exports.command = 'deploy [path]';
22
+ exports.command = 'deploy [--project] [--buildId]';
26
23
  exports.describe = i18n(`${i18nKey}.describe`);
27
24
 
28
25
  exports.handler = async options => {
29
26
  await loadAndValidateOptions(options);
30
27
 
31
- const { path: projectPath, buildId } = options;
32
28
  const accountId = getAccountId(options);
29
+ const { project, buildId } = options;
33
30
 
34
- trackCommandUsage('project-deploy', { projectPath }, accountId);
31
+ trackCommandUsage('project-deploy', { project }, accountId);
35
32
 
36
- const { projectConfig, projectDir } = await getProjectConfig(projectPath);
33
+ const { projectConfig } = await getProjectConfig();
37
34
 
38
- validateProjectConfig(projectConfig, projectDir);
35
+ let projectName = project;
39
36
 
40
- logger.debug(
41
- i18n(`${i18nKey}.debug.deploying`, {
42
- path: projectPath,
43
- })
44
- );
37
+ if (!projectName && projectConfig) {
38
+ projectName = projectConfig.name;
39
+ }
40
+
41
+ const namePrompt = await projectNamePrompt(accountId, {
42
+ project: projectName,
43
+ });
44
+
45
+ if (!projectName && namePrompt.projectName) {
46
+ projectName = namePrompt.projectName;
47
+ }
45
48
 
46
49
  let exitCode = EXIT_CODES.SUCCESS;
47
50
 
48
51
  const getBuildId = async () => {
49
- const { latestBuild } = await fetchProject(accountId, projectConfig.name);
52
+ const { latestBuild } = await fetchProject(accountId, projectName);
50
53
  if (latestBuild && latestBuild.buildId) {
51
54
  return latestBuild.buildId;
52
55
  }
@@ -60,7 +63,7 @@ exports.handler = async options => {
60
63
 
61
64
  const deployResp = await deployProject(
62
65
  accountId,
63
- projectConfig.name,
66
+ projectName,
64
67
  deployedBuildId
65
68
  );
66
69
 
@@ -76,7 +79,7 @@ exports.handler = async options => {
76
79
 
77
80
  await pollDeployStatus(
78
81
  accountId,
79
- projectConfig.name,
82
+ projectName,
80
83
  deployResp.id,
81
84
  deployedBuildId
82
85
  );
@@ -84,7 +87,7 @@ exports.handler = async options => {
84
87
  if (e.statusCode === 400) {
85
88
  logger.error(e.error.message);
86
89
  } else {
87
- logApiErrorInstance(e, new ApiErrorContext({ accountId, projectPath }));
90
+ logApiErrorInstance(e, new ApiErrorContext({ accountId, projectName }));
88
91
  }
89
92
  exitCode = 1;
90
93
  }
@@ -92,20 +95,23 @@ exports.handler = async options => {
92
95
  };
93
96
 
94
97
  exports.builder = yargs => {
95
- yargs.positional('path', {
96
- describe: i18n(`${i18nKey}.positionals.path.describe`),
97
- type: 'string',
98
- });
99
-
100
98
  yargs.options({
99
+ project: {
100
+ describe: i18n(`${i18nKey}.options.project.describe`),
101
+ type: 'string',
102
+ },
101
103
  buildId: {
102
104
  describe: i18n(`${i18nKey}.options.buildId.describe`),
103
105
  type: 'number',
104
106
  },
105
107
  });
106
108
 
109
+ yargs.example([['$0 project deploy', i18n(`${i18nKey}.examples.default`)]]);
107
110
  yargs.example([
108
- ['$0 project deploy myProjectFolder', i18n(`${i18nKey}.examples.default`)],
111
+ [
112
+ '$0 project deploy --project="my-project" --buildId=5',
113
+ i18n(`${i18nKey}.examples.withOptions`),
114
+ ],
109
115
  ]);
110
116
 
111
117
  addConfigOptions(yargs, true);
@@ -6,6 +6,7 @@ const {
6
6
  addUseEnvironmentOptions,
7
7
  addTestingOptions,
8
8
  } = require('../../lib/commonOpts');
9
+ const { trackCommandUsage } = require('../../lib/usageTracking');
9
10
  const { loadAndValidateOptions } = require('../../lib/validation');
10
11
  const { i18n } = require('@hubspot/cli-lib/lib/lang');
11
12
  const { logger } = require('@hubspot/cli-lib/logger');
@@ -27,6 +28,9 @@ exports.handler = async options => {
27
28
 
28
29
  const accountId = getAccountId(options);
29
30
  const { project } = options;
31
+
32
+ trackCommandUsage('project-open', { project }, accountId);
33
+
30
34
  const { projectConfig } = await getProjectConfig();
31
35
 
32
36
  let projectName = project;
@@ -42,7 +46,7 @@ exports.handler = async options => {
42
46
  } else if (!projectName && projectConfig) {
43
47
  projectName = projectConfig.name;
44
48
  } else if (!projectName && !projectConfig) {
45
- const namePrompt = await projectNamePrompt(accountId, projectConfig);
49
+ const namePrompt = await projectNamePrompt(accountId);
46
50
 
47
51
  if (!namePrompt.projectName) {
48
52
  process.exit(EXIT_CODES.ERROR);
@@ -3,6 +3,7 @@ const {
3
3
  addConfigOptions,
4
4
  getAccountId,
5
5
  addUseEnvironmentOptions,
6
+ addTestingOptions,
6
7
  } = require('../../lib/commonOpts');
7
8
  const { trackCommandUsage } = require('../../lib/usageTracking');
8
9
  const { logger } = require('@hubspot/cli-lib/logger');
@@ -11,9 +12,97 @@ const { createSandbox } = require('@hubspot/cli-lib/sandboxes');
11
12
  const { loadAndValidateOptions } = require('../../lib/validation');
12
13
  const { createSandboxPrompt } = require('../../lib/prompts/sandboxesPrompt');
13
14
  const { i18n } = require('@hubspot/cli-lib/lib/lang');
15
+ const { logErrorInstance } = require('@hubspot/cli-lib/errorHandlers');
16
+ const {
17
+ ENVIRONMENTS,
18
+ PERSONAL_ACCESS_KEY_AUTH_METHOD,
19
+ DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME,
20
+ } = require('@hubspot/cli-lib/lib/constants');
21
+ const {
22
+ personalAccessKeyPrompt,
23
+ } = require('../../lib/prompts/personalAccessKeyPrompt');
24
+ const {
25
+ updateConfigWithPersonalAccessKey,
26
+ } = require('@hubspot/cli-lib/personalAccessKey');
27
+ const { EXIT_CODES } = require('../../lib/enums/exitCodes');
28
+ const {
29
+ getConfig,
30
+ writeConfig,
31
+ updateAccountConfig,
32
+ getAccountConfig,
33
+ } = require('@hubspot/cli-lib');
34
+ const {
35
+ enterAccountNamePrompt,
36
+ } = require('../../lib/prompts/enterAccountNamePrompt');
37
+ const {
38
+ setAsDefaultAccountPrompt,
39
+ } = require('../../lib/prompts/setAsDefaultAccountPrompt');
40
+ const { getHubSpotWebsiteOrigin } = require('@hubspot/cli-lib/lib/urls');
41
+ const {
42
+ isMissingScopeError,
43
+ } = require('@hubspot/cli-lib/errorHandlers/apiErrors');
44
+ const { uiFeatureHighlight } = require('../../lib/ui');
14
45
 
15
46
  const i18nKey = 'cli.commands.sandbox.subcommands.create';
16
47
 
48
+ const personalAccessKeyFlow = async (env, account, name) => {
49
+ const configData = await personalAccessKeyPrompt({ env, account });
50
+ const updatedConfig = await updateConfigWithPersonalAccessKey(configData);
51
+
52
+ if (!updatedConfig) {
53
+ process.exit(EXIT_CODES.SUCCESS);
54
+ }
55
+
56
+ let validName = updatedConfig.name;
57
+
58
+ if (!updatedConfig.name) {
59
+ const nameForConfig = name
60
+ .toLowerCase()
61
+ .split(' ')
62
+ .join('-');
63
+ const { name: promptName } = await enterAccountNamePrompt(nameForConfig);
64
+ validName = promptName;
65
+ }
66
+
67
+ updateAccountConfig({
68
+ ...updatedConfig,
69
+ environment: updatedConfig.env,
70
+ tokenInfo: updatedConfig.auth.tokenInfo,
71
+ name: validName,
72
+ });
73
+ writeConfig();
74
+
75
+ const setAsDefault = await setAsDefaultAccountPrompt(validName);
76
+
77
+ logger.log('');
78
+ if (setAsDefault) {
79
+ logger.success(
80
+ i18n(`cli.lib.prompts.setAsDefaultAccountPrompt.setAsDefaultAccount`, {
81
+ accountName: validName,
82
+ })
83
+ );
84
+ } else {
85
+ const config = getConfig();
86
+ logger.info(
87
+ i18n(`cli.lib.prompts.setAsDefaultAccountPrompt.keepingCurrentDefault`, {
88
+ accountName: config.defaultPortal,
89
+ })
90
+ );
91
+ }
92
+ logger.success(
93
+ i18n(`${i18nKey}.success.configFileUpdated`, {
94
+ configFilename: DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME,
95
+ authMethod: PERSONAL_ACCESS_KEY_AUTH_METHOD.name,
96
+ account: validName,
97
+ })
98
+ );
99
+ uiFeatureHighlight([
100
+ 'accountsUseCommand',
101
+ 'accountOption',
102
+ 'accountsListCommand',
103
+ ]);
104
+ };
105
+
17
106
  exports.command = 'create [name]';
18
107
  exports.describe = i18n(`${i18nKey}.describe`);
19
108
 
@@ -22,6 +111,8 @@ exports.handler = async options => {
22
111
 
23
112
  const { name } = options;
24
113
  const accountId = getAccountId(options);
114
+ const accountConfig = getAccountConfig(accountId);
115
+ const env = options.qa ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD;
25
116
  let namePrompt;
26
117
 
27
118
  trackCommandUsage('sandbox-create', {}, accountId);
@@ -37,18 +128,46 @@ exports.handler = async options => {
37
128
  name: sandboxName,
38
129
  })
39
130
  );
40
-
41
- return createSandbox(accountId, sandboxName).then(
42
- ({ name, sandboxHubId }) => {
43
- logger.success(
44
- i18n(`${i18nKey}.success.create`, {
45
- name,
46
- sandboxHubId,
131
+ let result;
132
+ try {
133
+ result = await createSandbox(accountId, sandboxName).then(
134
+ ({ name, sandboxHubId }) => {
135
+ logger.log('');
136
+ logger.success(
137
+ i18n(`${i18nKey}.success.create`, {
138
+ name,
139
+ sandboxHubId,
140
+ })
141
+ );
142
+ return { name, sandboxHubId };
143
+ }
144
+ );
145
+ } catch (err) {
146
+ if (isMissingScopeError(err)) {
147
+ logger.error(
148
+ i18n(`${i18nKey}.failure.scopes.message`, {
149
+ accountName: accountConfig.name || accountId,
150
+ })
151
+ );
152
+ const websiteOrigin = getHubSpotWebsiteOrigin(env);
153
+ const url = `${websiteOrigin}/personal-access-key/${accountId}`;
154
+ logger.info(
155
+ i18n(`${i18nKey}.failure.scopes.instructions`, {
156
+ accountName: accountConfig.name || accountId,
157
+ url,
47
158
  })
48
159
  );
49
- logger.info(i18n(`${i18nKey}.info.auth`));
160
+ } else {
161
+ logger.error(err.error.message);
50
162
  }
51
- );
163
+ process.exit(EXIT_CODES.ERROR);
164
+ }
165
+ try {
166
+ await personalAccessKeyFlow(env, result.sandboxHubId, result.name);
167
+ process.exit(EXIT_CODES.SUCCESS);
168
+ } catch (err) {
169
+ logErrorInstance(err);
170
+ }
52
171
  };
53
172
 
54
173
  exports.builder = yargs => {
@@ -64,6 +183,7 @@ exports.builder = yargs => {
64
183
  addConfigOptions(yargs, true);
65
184
  addAccountOptions(yargs, true);
66
185
  addUseEnvironmentOptions(yargs, true);
186
+ addTestingOptions(yargs, true);
67
187
 
68
188
  return yargs;
69
189
  };
@@ -0,0 +1,41 @@
1
+ const {
2
+ addAccountOptions,
3
+ addConfigOptions,
4
+ addUseEnvironmentOptions,
5
+ } = require('../../lib/commonOpts');
6
+ const { logger } = require('@hubspot/cli-lib/logger');
7
+
8
+ const { loadAndValidateOptions } = require('../../lib/validation');
9
+ const { i18n } = require('@hubspot/cli-lib/lib/lang');
10
+
11
+ const i18nKey = 'cli.commands.sandbox.subcommands.delete';
12
+
13
+ exports.command = 'delete';
14
+ exports.describe = i18n(`${i18nKey}.describe`);
15
+
16
+ exports.handler = async options => {
17
+ await loadAndValidateOptions(options);
18
+
19
+ logger.log('');
20
+ logger.log(i18n(`${i18nKey}.temporaryMessage`));
21
+ };
22
+
23
+ exports.builder = yargs => {
24
+ yargs.option('account', {
25
+ describe: i18n(`${i18nKey}.options.account.describe`),
26
+ type: 'string',
27
+ });
28
+
29
+ yargs.example([
30
+ [
31
+ '$0 sandbox delete --account=MySandboxAccount',
32
+ i18n(`${i18nKey}.examples.default`),
33
+ ],
34
+ ]);
35
+
36
+ addConfigOptions(yargs, true);
37
+ addAccountOptions(yargs, true);
38
+ addUseEnvironmentOptions(yargs, true);
39
+
40
+ return yargs;
41
+ };
@@ -1,5 +1,6 @@
1
1
  const { addConfigOptions, addAccountOptions } = require('../lib/commonOpts');
2
2
  const create = require('./sandbox/create');
3
+ const del = require('./sandbox/delete');
3
4
 
4
5
  // const i18nKey = 'cli.commands.sandbox';
5
6
 
@@ -10,7 +11,10 @@ exports.builder = yargs => {
10
11
  addConfigOptions(yargs, true);
11
12
  addAccountOptions(yargs, true);
12
13
 
13
- yargs.command(create).demandCommand(1, '');
14
+ yargs
15
+ .command(create)
16
+ .command(del)
17
+ .demandCommand(1, '');
14
18
 
15
19
  return yargs;
16
20
  };
package/lib/projects.js CHANGED
@@ -165,7 +165,7 @@ const validateProjectConfig = (projectConfig, projectDir) => {
165
165
  const ensureProjectExists = async (
166
166
  accountId,
167
167
  projectName,
168
- { forceCreate = false, allowCreate = true } = {}
168
+ { forceCreate = false, allowCreate = true, noLogs = false } = {}
169
169
  ) => {
170
170
  try {
171
171
  const project = await fetchProject(accountId, projectName);
@@ -194,11 +194,13 @@ const ensureProjectExists = async (
194
194
  return logApiErrorInstance(err, new ApiErrorContext({ accountId }));
195
195
  }
196
196
  } else {
197
- logger.log(
198
- `Your project ${chalk.bold(
199
- projectName
200
- )} could not be found in ${chalk.bold(accountId)}.`
201
- );
197
+ if (!noLogs) {
198
+ logger.log(
199
+ `Your project ${chalk.bold(
200
+ projectName
201
+ )} could not be found in ${chalk.bold(accountId)}.`
202
+ );
203
+ }
202
204
  return false;
203
205
  }
204
206
  }
@@ -324,26 +326,6 @@ const handleProjectUpload = async (
324
326
  archive.finalize();
325
327
  };
326
328
 
327
- const showProjectWelcomeMessage = () => {
328
- logger.log('');
329
- logger.log(chalk.bold('Welcome to HubSpot Developer Projects!'));
330
- logger.log('\n');
331
- uiLine();
332
- logger.log('\n');
333
- logger.log(chalk.bold("What's next?\n"));
334
- logger.log('🎨 Add components to your project with `hs create`.\n');
335
- logger.log(
336
- `🏗 Run \`hs project upload\` to upload your files to HubSpot and trigger builds.\n`
337
- );
338
- logger.log(
339
- `🚀 Ready to take your project live? Run \`hs project deploy\`.\n`
340
- );
341
- logger.log(
342
- `🔗 Use \`hs project --help\` to learn more about available commands.\n`
343
- );
344
- uiLine();
345
- };
346
-
347
329
  const makePollTaskStatusFunc = ({
348
330
  statusFn,
349
331
  statusText,
@@ -467,6 +449,14 @@ const makePollTaskStatusFunc = ({
467
449
  } with the following error ---`
468
450
  );
469
451
  logger.error(subTask.errorMessage);
452
+
453
+ // Log nested errors
454
+ if (subTask.standardError && subTask.standardError.errors) {
455
+ logger.log();
456
+ subTask.standardError.errors.forEach(error => {
457
+ logger.log(error.message);
458
+ });
459
+ }
470
460
  });
471
461
  }
472
462
 
@@ -519,7 +509,6 @@ module.exports = {
519
509
  handleProjectUpload,
520
510
  createProjectConfig,
521
511
  validateProjectConfig,
522
- showProjectWelcomeMessage,
523
512
  getProjectDetailUrl,
524
513
  getProjectBuildDetailUrl,
525
514
  pollBuildStatus,
@@ -0,0 +1,33 @@
1
+ const { accountNameExistsInConfig } = require('@hubspot/cli-lib/lib/config');
2
+ const { STRING_WITH_NO_SPACES_REGEX } = require('../regex');
3
+ const { promptUser } = require('./promptUtils');
4
+ const { i18n } = require('@hubspot/cli-lib/lib/lang');
5
+
6
+ const i18nKey = 'cli.lib.prompts.enterAccountNamePrompt';
7
+
8
+ const accountNamePrompt = defaultName => ({
9
+ name: 'name',
10
+ message: i18n(`${i18nKey}.enterAccountName`),
11
+ default: defaultName,
12
+ validate(val) {
13
+ if (typeof val !== 'string') {
14
+ return i18n(`${i18nKey}.errors.invalidName`);
15
+ } else if (!val.length) {
16
+ return i18n(`${i18nKey}.errors.nameRequired`);
17
+ } else if (!STRING_WITH_NO_SPACES_REGEX.test(val)) {
18
+ return i18n(`${i18nKey}.errors.spacesInName`);
19
+ }
20
+ return accountNameExistsInConfig(val)
21
+ ? i18n(`${i18nKey}.errors.accountNameExists`, { name: val })
22
+ : true;
23
+ },
24
+ });
25
+
26
+ const enterAccountNamePrompt = defaultName => {
27
+ return promptUser(accountNamePrompt(defaultName));
28
+ };
29
+
30
+ module.exports = {
31
+ accountNamePrompt,
32
+ enterAccountNamePrompt,
33
+ };
@@ -3,11 +3,15 @@ const {
3
3
  OAUTH_SCOPES,
4
4
  DEFAULT_OAUTH_SCOPES,
5
5
  } = require('@hubspot/cli-lib/lib/constants');
6
+ const { deleteEmptyConfigFile } = require('@hubspot/cli-lib/lib/config');
6
7
  const { getHubSpotWebsiteOrigin } = require('@hubspot/cli-lib/lib/urls');
7
8
  const { logger } = require('@hubspot/cli-lib/logger');
8
- const { API_KEY_REGEX, STRING_WITH_NO_SPACES_REGEX } = require('../regex');
9
+ const { API_KEY_REGEX } = require('../regex');
9
10
  const { promptUser } = require('./promptUtils');
11
+ const { accountNamePrompt } = require('./enterAccountNamePrompt');
10
12
  const { i18n } = require('@hubspot/cli-lib/lib/lang');
13
+ const { uiInfoSection } = require('../ui');
14
+ const { EXIT_CODES } = require('../enums/exitCodes');
11
15
 
12
16
  const i18nKey = 'cli.lib.prompts.personalAccessKeyPrompt';
13
17
 
@@ -15,12 +19,25 @@ const i18nKey = 'cli.lib.prompts.personalAccessKeyPrompt';
15
19
  * Displays notification to user that we are about to open the browser,
16
20
  * then opens their browser to the personal-access-key shortlink
17
21
  */
18
- const personalAccessKeyPrompt = async ({ env } = {}) => {
22
+ const personalAccessKeyPrompt = async ({ env, account } = {}) => {
19
23
  const websiteOrigin = getHubSpotWebsiteOrigin(env);
20
- const url = `${websiteOrigin}/l/personal-access-key`;
24
+ let url = `${websiteOrigin}/l/personal-access-key`;
21
25
  if (process.env.BROWSER !== 'none') {
22
- await promptUser([PERSONAL_ACCESS_KEY_BROWSER_OPEN_PREP]);
23
- open(url, { url: true });
26
+ uiInfoSection(i18n(`${i18nKey}.personalAccessKeySetupTitle`), () => {
27
+ logger.log(i18n(`${i18nKey}.personalAccessKeyBrowserOpenPrep`));
28
+ });
29
+ if (account) {
30
+ url = `${websiteOrigin}/personal-access-key/${account}`;
31
+ }
32
+ const { personalAcessKeyBrowserOpenPrep: shouldOpen } = await promptUser([
33
+ PERSONAL_ACCESS_KEY_BROWSER_OPEN_PREP,
34
+ ]);
35
+ if (shouldOpen) {
36
+ open(url, { url: true });
37
+ } else {
38
+ deleteEmptyConfigFile();
39
+ process.exit(EXIT_CODES.SUCCESS);
40
+ }
24
41
  }
25
42
 
26
43
  logger.log(i18n(`${i18nKey}.logs.openingWebBrowser`, { url }));
@@ -72,21 +89,6 @@ const CLIENT_SECRET = {
72
89
  },
73
90
  };
74
91
 
75
- const ACCOUNT_NAME = {
76
- name: 'name',
77
- message: i18n(`${i18nKey}.enterAccountName`),
78
- validate(val) {
79
- if (typeof val !== 'string') {
80
- return i18n(`${i18nKey}.errors.invalidName`);
81
- } else if (!val.length) {
82
- return i18n(`${i18nKey}.errors.nameRequired`);
83
- } else if (!STRING_WITH_NO_SPACES_REGEX.test(val)) {
84
- return i18n(`${i18nKey}.errors.spacesInName`);
85
- }
86
- return true;
87
- },
88
- };
89
-
90
92
  const ACCOUNT_API_KEY = {
91
93
  name: 'apiKey',
92
94
  message: i18n(`${i18nKey}.enterApiKey`),
@@ -100,12 +102,21 @@ const ACCOUNT_API_KEY = {
100
102
 
101
103
  const PERSONAL_ACCESS_KEY_BROWSER_OPEN_PREP = {
102
104
  name: 'personalAcessKeyBrowserOpenPrep',
103
- message: i18n(`${i18nKey}.personalAccessKeyBrowserOpenPrep`),
105
+ type: 'confirm',
106
+ message: i18n(`${i18nKey}.personalAccessKeyBrowserOpenPrompt`),
104
107
  };
105
108
 
106
109
  const PERSONAL_ACCESS_KEY = {
107
110
  name: 'personalAccessKey',
108
111
  message: i18n(`${i18nKey}.enterPersonalAccessKey`),
112
+ transformer: val => {
113
+ if (!val) return val;
114
+ let res = '';
115
+ for (let i = 0; i < val.length; i++) {
116
+ res += '*';
117
+ }
118
+ return res;
119
+ },
109
120
  validate(val) {
110
121
  if (!val || typeof val !== 'string') {
111
122
  return i18n(`${i18nKey}.errors.invalidPersonalAccessKey`);
@@ -124,8 +135,14 @@ const SCOPES = {
124
135
  choices: OAUTH_SCOPES,
125
136
  };
126
137
 
127
- const OAUTH_FLOW = [ACCOUNT_NAME, ACCOUNT_ID, CLIENT_ID, CLIENT_SECRET, SCOPES];
128
- const API_KEY_FLOW = [ACCOUNT_NAME, ACCOUNT_ID, ACCOUNT_API_KEY];
138
+ const OAUTH_FLOW = [
139
+ accountNamePrompt(),
140
+ ACCOUNT_ID,
141
+ CLIENT_ID,
142
+ CLIENT_SECRET,
143
+ SCOPES,
144
+ ];
145
+ const API_KEY_FLOW = [accountNamePrompt(), ACCOUNT_ID, ACCOUNT_API_KEY];
129
146
 
130
147
  module.exports = {
131
148
  personalAccessKeyPrompt,
@@ -133,10 +150,8 @@ module.exports = {
133
150
  CLIENT_SECRET,
134
151
  ACCOUNT_API_KEY,
135
152
  ACCOUNT_ID,
136
- ACCOUNT_NAME,
137
153
  SCOPES,
138
154
  PERSONAL_ACCESS_KEY,
139
-
140
155
  // Flows
141
156
  API_KEY_FLOW,
142
157
  OAUTH_FLOW,
@@ -4,20 +4,24 @@ const { ensureProjectExists } = require('../projects');
4
4
 
5
5
  const i18nKey = 'cli.lib.prompts.projectNamePrompt';
6
6
 
7
- const projectNamePrompt = accountId => {
7
+ const projectNamePrompt = (accountId, options = {}) => {
8
8
  return promptUser({
9
9
  name: 'projectName',
10
10
  message: i18n(`${i18nKey}.enterName`),
11
+ when: !options.project,
11
12
  validate: async val => {
12
- if (typeof val !== 'string') {
13
+ if (typeof val !== 'string' || !val) {
13
14
  return i18n(`${i18nKey}.errors.invalidName`);
14
15
  }
15
16
  const projectExists = await ensureProjectExists(accountId, val, {
16
17
  allowCreate: false,
18
+ noLogs: true,
17
19
  });
18
-
19
20
  if (!projectExists) {
20
- return false;
21
+ return i18n(`${i18nKey}.errors.projectDoesNotExist`, {
22
+ projectName: val,
23
+ accountId,
24
+ });
21
25
  }
22
26
  return true;
23
27
  },
@@ -0,0 +1,30 @@
1
+ const {
2
+ getConfig,
3
+ updateDefaultAccount,
4
+ } = require('@hubspot/cli-lib/lib/config');
5
+ const { promptUser } = require('./promptUtils');
6
+ const { i18n } = require('@hubspot/cli-lib/lib/lang');
7
+
8
+ const i18nKey = 'cli.lib.prompts.setAsDefaultAccountPrompt';
9
+
10
+ const setAsDefaultAccountPrompt = async accountName => {
11
+ const config = getConfig();
12
+
13
+ const { setAsDefault } = await promptUser([
14
+ {
15
+ name: 'setAsDefault',
16
+ type: 'confirm',
17
+ when: config.defaultPortal !== accountName,
18
+ message: i18n(`${i18nKey}.setAsDefaultAccountMessage`),
19
+ },
20
+ ]);
21
+
22
+ if (setAsDefault) {
23
+ updateDefaultAccount(accountName);
24
+ }
25
+ return setAsDefault;
26
+ };
27
+
28
+ module.exports = {
29
+ setAsDefaultAccountPrompt,
30
+ };
package/lib/ui.js CHANGED
@@ -2,6 +2,7 @@ const chalk = require('chalk');
2
2
  const supportsHyperlinks = require('../lib/supportHyperlinks');
3
3
  const supportsColor = require('../lib/supportsColor');
4
4
  const { getAccountConfig } = require('@hubspot/cli-lib/lib/config');
5
+ const { i18n } = require('@hubspot/cli-lib/lib/lang');
5
6
  const { logger } = require('@hubspot/cli-lib/logger');
6
7
 
7
8
  /**
@@ -65,8 +66,36 @@ const uiAccountDescription = accountId => {
65
66
  );
66
67
  };
67
68
 
69
+ const uiInfoSection = (title, logContent) => {
70
+ uiLine();
71
+ logger.log(chalk.bold(title));
72
+ logger.log('');
73
+ logContent();
74
+ logger.log('');
75
+ uiLine();
76
+ };
77
+
78
+ const uiFeatureHighlight = (commands, title) => {
79
+ const i18nKey = 'cli.lib.ui.featureHighlight';
80
+
81
+ uiInfoSection(title ? title : i18n(`${i18nKey}.defaultTitle`), () => {
82
+ commands.forEach((c, i) => {
83
+ const commandKey = `${i18nKey}.commandKeys.${c}`;
84
+ const message = i18n(`${commandKey}.message`, {
85
+ command: chalk.bold(i18n(`${commandKey}.command`)),
86
+ });
87
+ if (i !== 0) {
88
+ logger.log('');
89
+ }
90
+ logger.log(message);
91
+ });
92
+ });
93
+ };
94
+
68
95
  module.exports = {
96
+ uiAccountDescription,
97
+ uiFeatureHighlight,
98
+ uiInfoSection,
69
99
  uiLine,
70
100
  uiLink,
71
- uiAccountDescription,
72
101
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubspot/cli",
3
- "version": "4.0.0",
3
+ "version": "4.0.1-beta.2",
4
4
  "description": "CLI for working with HubSpot",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -8,8 +8,8 @@
8
8
  "url": "https://github.com/HubSpot/hubspot-cms-tools"
9
9
  },
10
10
  "dependencies": {
11
- "@hubspot/cli-lib": "4.0.0",
12
- "@hubspot/serverless-dev-runtime": "4.0.0",
11
+ "@hubspot/cli-lib": "4.0.1-beta.2",
12
+ "@hubspot/serverless-dev-runtime": "4.0.1-beta.2",
13
13
  "archiver": "^5.3.0",
14
14
  "chalk": "^4.1.2",
15
15
  "express": "^4.17.1",
@@ -37,5 +37,5 @@
37
37
  "publishConfig": {
38
38
  "access": "public"
39
39
  },
40
- "gitHead": "c11f159c8768c0a0beac7b221d4c2489bcf0064d"
40
+ "gitHead": "c8b5dbfe4753fc1b71c038801d5f641313712e71"
41
41
  }