@hubspot/cli 4.2.1-beta.4 → 5.0.1-beta.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.
package/commands/auth.js CHANGED
@@ -31,16 +31,23 @@ const {
31
31
  const {
32
32
  addConfigOptions,
33
33
  setLogLevel,
34
+ getAccountId,
34
35
  addTestingOptions,
35
36
  } = require('../lib/commonOpts');
36
37
  const { logDebugInfo } = require('../lib/debugInfo');
37
- const { trackCommandUsage } = require('../lib/usageTracking');
38
+ const { trackAuthAction, trackCommandUsage } = require('../lib/usageTracking');
38
39
  const { authenticateWithOauth } = require('../lib/oauth');
39
40
  const { EXIT_CODES } = require('../lib/enums/exitCodes');
40
41
  const { uiFeatureHighlight } = require('../lib/ui');
41
42
 
42
43
  const i18nKey = 'cli.commands.auth';
43
44
 
45
+ const TRACKING_STATUS = {
46
+ STARTED: 'started',
47
+ ERROR: 'error',
48
+ COMPLETE: 'complete',
49
+ };
50
+
44
51
  const ALLOWED_AUTH_METHODS = [
45
52
  OAUTH_AUTH_METHOD.value,
46
53
  PERSONAL_ACCESS_KEY_AUTH_METHOD.value,
@@ -71,6 +78,7 @@ exports.handler = async options => {
71
78
  checkAndWarnGitInclusion(getConfigPath());
72
79
 
73
80
  trackCommandUsage('auth');
81
+ trackAuthAction('auth', authType, TRACKING_STATUS.STARTED);
74
82
 
75
83
  let configData;
76
84
  let updatedConfig;
@@ -122,6 +130,7 @@ exports.handler = async options => {
122
130
  }
123
131
 
124
132
  if (!successAuthMethod) {
133
+ await trackAuthAction('auth', authType, TRACKING_STATUS.ERROR);
125
134
  process.exit(EXIT_CODES.ERROR);
126
135
  }
127
136
 
@@ -157,6 +166,9 @@ exports.handler = async options => {
157
166
  'accountsListCommand',
158
167
  ]);
159
168
 
169
+ const accountId = getAccountId({ account: accountName });
170
+ await trackAuthAction('auth', authType, TRACKING_STATUS.COMPLETE, accountId);
171
+
160
172
  process.exit(EXIT_CODES.SUCCESS);
161
173
  };
162
174
 
@@ -76,6 +76,8 @@ exports.handler = async options => {
76
76
  const argsToPass = { assetType, name, dest, options };
77
77
  dest = argsToPass.dest = resolveLocalPath(asset.dest(argsToPass));
78
78
 
79
+ trackCommandUsage('create', { assetType }, getAccountId(options));
80
+
79
81
  try {
80
82
  await fs.ensureDir(dest);
81
83
  } catch (e) {
@@ -94,8 +96,6 @@ exports.handler = async options => {
94
96
  if (asset.validate && !asset.validate(argsToPass)) return;
95
97
 
96
98
  await asset.execute(argsToPass);
97
-
98
- trackCommandUsage('create', { assetType }, getAccountId(options));
99
99
  };
100
100
 
101
101
  exports.builder = yargs => {
@@ -1,28 +1,24 @@
1
- const chalk = require('chalk');
2
1
  const { addConfigOptions, addAccountOptions } = require('../lib/commonOpts');
3
2
  const schemaCommand = require('./customObject/schema');
4
3
  const createCommand = require('./customObject/create');
5
4
  const { i18n } = require('../lib/lang');
6
5
  const { logger } = require('@hubspot/cli-lib/logger');
7
- const { uiBetaWarning } = require('../lib/ui');
6
+ const { uiBetaTag, uiLink } = require('../lib/ui');
8
7
 
9
8
  const i18nKey = 'cli.commands.customObject';
10
9
 
11
10
  exports.command = ['custom-object', 'custom', 'co'];
12
- exports.describe = i18n(`${i18nKey}.describe`);
11
+ exports.describe = uiBetaTag(i18n(`${i18nKey}.describe`), false);
13
12
 
14
13
  const logBetaMessage = () => {
15
- uiBetaWarning(() => {
16
- logger.log(chalk.reset.yellow(i18n(`${i18nKey}.betaMessage`)));
17
- logger.log(
18
- chalk.reset.yellow(
19
- i18n(`${i18nKey}.seeMoreLink`, {
20
- link:
21
- 'https://developers.hubspot.com/docs/api/crm/crm-custom-objects',
22
- })
23
- )
24
- );
25
- });
14
+ uiBetaTag(i18n(`${i18nKey}.betaMessage`));
15
+ logger.log(
16
+ uiLink(
17
+ i18n(`${i18nKey}.seeMoreLink`),
18
+ 'https://developers.hubspot.com/docs/api/crm/crm-custom-objects'
19
+ )
20
+ );
21
+ logger.log();
26
22
  };
27
23
 
28
24
  exports.builder = yargs => {
package/commands/init.js CHANGED
@@ -133,11 +133,17 @@ exports.handler = async options => {
133
133
  );
134
134
  uiFeatureHighlight(['helpCommand', 'authCommand', 'accountsListCommand']);
135
135
 
136
- trackAuthAction('init', authType, TRACKING_STATUS.COMPLETE, accountId);
136
+ await trackAuthAction(
137
+ 'init',
138
+ authType,
139
+ TRACKING_STATUS.COMPLETE,
140
+ accountId
141
+ );
137
142
  process.exit(EXIT_CODES.SUCCESS);
138
143
  } catch (err) {
139
144
  logErrorInstance(err);
140
- trackAuthAction('init', authType, TRACKING_STATUS.ERROR);
145
+ await trackAuthAction('init', authType, TRACKING_STATUS.ERROR);
146
+ process.exit(EXIT_CODES.ERROR);
141
147
  }
142
148
  };
143
149
 
package/commands/mv.js CHANGED
@@ -15,6 +15,7 @@ const { trackCommandUsage } = require('../lib/usageTracking');
15
15
  const { isPathFolder } = require('../lib/filesystem');
16
16
  const { loadAndValidateOptions } = require('../lib/validation');
17
17
  const { i18n } = require('../lib/lang');
18
+ const { uiBetaTag } = require('../lib/ui');
18
19
 
19
20
  const i18nKey = 'cli.commands.mv';
20
21
 
@@ -28,7 +29,7 @@ const getCorrectedDestPath = (srcPath, destPath) => {
28
29
  };
29
30
 
30
31
  exports.command = 'mv <srcPath> <destPath>';
31
- exports.describe = i18n(`${i18nKey}.describe`);
32
+ exports.describe = uiBetaTag(i18n(`${i18nKey}.describe`), false);
32
33
 
33
34
  exports.handler = async options => {
34
35
  await loadAndValidateOptions(options);
@@ -7,11 +7,12 @@ const { i18n } = require('../../lib/lang');
7
7
  const { projectAddPrompt } = require('../../lib/prompts/projectAddPrompt');
8
8
  const { createProjectComponent } = require('../../lib/projects');
9
9
  const { loadAndValidateOptions } = require('../../lib/validation');
10
+ const { uiBetaTag } = require('../../lib/ui');
10
11
 
11
12
  const i18nKey = 'cli.commands.project.subcommands.add';
12
13
 
13
14
  exports.command = 'add';
14
- exports.describe = i18n(`${i18nKey}.describe`);
15
+ exports.describe = uiBetaTag(i18n(`${i18nKey}.describe`), false);
15
16
 
16
17
  exports.handler = async options => {
17
18
  await loadAndValidateOptions(options);
@@ -14,13 +14,13 @@ const {
14
14
  } = require('../../lib/prompts/createProjectPrompt');
15
15
  const { createProjectConfig } = require('../../lib/projects');
16
16
  const { i18n } = require('../../lib/lang');
17
- const { uiFeatureHighlight } = require('../../lib/ui');
17
+ const { uiBetaTag, uiFeatureHighlight } = require('../../lib/ui');
18
18
  const { logger } = require('@hubspot/cli-lib/logger');
19
19
 
20
20
  const i18nKey = 'cli.commands.project.subcommands.create';
21
21
 
22
22
  exports.command = 'create';
23
- exports.describe = i18n(`${i18nKey}.describe`);
23
+ exports.describe = uiBetaTag(i18n(`${i18nKey}.describe`), false);
24
24
 
25
25
  exports.handler = async options => {
26
26
  await loadAndValidateOptions(options);
@@ -45,8 +45,7 @@ exports.handler = async options => {
45
45
  logger.log('');
46
46
  logger.log(chalk.bold(i18n(`${i18nKey}.logs.welcomeMessage`)));
47
47
  uiFeatureHighlight([
48
- 'projectUploadCommand',
49
- 'projectDeployCommand',
48
+ 'projectDevCommand',
50
49
  'projectHelpCommand',
51
50
  'feedbackCommand',
52
51
  ]);
@@ -1,3 +1,4 @@
1
+ const chalk = require('chalk');
1
2
  const {
2
3
  addAccountOptions,
3
4
  addConfigOptions,
@@ -16,13 +17,15 @@ const { getProjectConfig, pollDeployStatus } = require('../../lib/projects');
16
17
  const { projectNamePrompt } = require('../../lib/prompts/projectNamePrompt');
17
18
  const { buildIdPrompt } = require('../../lib/prompts/buildIdPrompt');
18
19
  const { i18n } = require('../../lib/lang');
20
+ const { uiBetaTag } = require('../../lib/ui');
19
21
  const { getAccountConfig } = require('@hubspot/cli-lib');
20
22
 
21
23
  const i18nKey = 'cli.commands.project.subcommands.deploy';
22
24
  const { EXIT_CODES } = require('../../lib/enums/exitCodes');
25
+ const { uiCommandReference, uiAccountDescription } = require('../../lib/ui');
23
26
 
24
27
  exports.command = 'deploy [--project] [--buildId]';
25
- exports.describe = i18n(`${i18nKey}.describe`);
28
+ exports.describe = uiBetaTag(i18n(`${i18nKey}.describe`), false);
26
29
 
27
30
  exports.handler = async options => {
28
31
  await loadAndValidateOptions(options);
@@ -98,6 +101,15 @@ exports.handler = async options => {
98
101
  buildIdToDeploy
99
102
  );
100
103
  } catch (e) {
104
+ if (e.statusCode === 404) {
105
+ logger.error(
106
+ i18n(`${i18nKey}.errors.projectNotFound`, {
107
+ projectName: chalk.bold(projectName),
108
+ accountIdentifier: uiAccountDescription(accountId),
109
+ command: uiCommandReference('hs project upload'),
110
+ })
111
+ );
112
+ }
101
113
  if (e.statusCode === 400) {
102
114
  logger.error(e.error.message);
103
115
  } else {
@@ -25,7 +25,7 @@ const {
25
25
  const { EXIT_CODES } = require('../../lib/enums/exitCodes');
26
26
  const {
27
27
  uiAccountDescription,
28
- uiBetaMessage,
28
+ uiBetaTag,
29
29
  uiCommandReference,
30
30
  uiLine,
31
31
  } = require('../../lib/ui');
@@ -66,7 +66,7 @@ const {
66
66
  const i18nKey = 'cli.commands.project.subcommands.dev';
67
67
 
68
68
  exports.command = 'dev [--account]';
69
- exports.describe = i18n(`${i18nKey}.describe`);
69
+ exports.describe = uiBetaTag(i18n(`${i18nKey}.describe`), false);
70
70
 
71
71
  exports.handler = async options => {
72
72
  await loadAndValidateOptions(options);
@@ -78,7 +78,7 @@ exports.handler = async options => {
78
78
 
79
79
  const { projectConfig, projectDir } = await getProjectConfig();
80
80
 
81
- uiBetaMessage(i18n(`${i18nKey}.logs.betaMessage`));
81
+ uiBetaTag(i18n(`${i18nKey}.logs.betaMessage`));
82
82
 
83
83
  if (!projectConfig) {
84
84
  logger.error(i18n(`${i18nKey}.errors.noProjectConfig`));
@@ -200,10 +200,14 @@ exports.handler = async options => {
200
200
  );
201
201
 
202
202
  let deployedBuild;
203
+ let isGithubLinked;
203
204
 
204
205
  if (projectExists) {
205
206
  const project = await fetchProject(targetAccountId, projectConfig.name);
206
207
  deployedBuild = project.deployedBuild;
208
+ isGithubLinked =
209
+ project.sourceIntegration &&
210
+ project.sourceIntegration.source === 'GITHUB';
207
211
  }
208
212
 
209
213
  SpinniesManager.init();
@@ -327,6 +331,7 @@ exports.handler = async options => {
327
331
  projectConfig,
328
332
  projectDir,
329
333
  targetAccountId,
334
+ isGithubLinked,
330
335
  });
331
336
 
332
337
  await LocalDev.start();
@@ -23,12 +23,13 @@ const {
23
23
  downloadProjectPrompt,
24
24
  } = require('../../lib/prompts/downloadProjectPrompt');
25
25
  const { i18n } = require('../../lib/lang');
26
+ const { uiBetaTag } = require('../../lib/ui');
26
27
 
27
28
  const i18nKey = 'cli.commands.project.subcommands.download';
28
29
  const { EXIT_CODES } = require('../../lib/enums/exitCodes');
29
30
 
30
31
  exports.command = 'download [--project]';
31
- exports.describe = i18n(`${i18nKey}.describe`);
32
+ exports.describe = uiBetaTag(i18n(`${i18nKey}.describe`), false);
32
33
 
33
34
  exports.handler = async options => {
34
35
  await loadAndValidateOptions(options);
@@ -22,7 +22,7 @@ const {
22
22
  getTableHeader,
23
23
  } = require('@hubspot/cli-lib/lib/table');
24
24
  const { getCwd } = require('@hubspot/cli-lib/path');
25
- const { uiLink } = require('../../lib/ui');
25
+ const { uiBetaTag, uiLink } = require('../../lib/ui');
26
26
  const { loadAndValidateOptions } = require('../../lib/validation');
27
27
  const {
28
28
  getProjectConfig,
@@ -35,7 +35,7 @@ const { promptUser } = require('../../lib/prompts/promptUtils');
35
35
  const i18nKey = 'cli.commands.project.subcommands.listBuilds';
36
36
 
37
37
  exports.command = 'list-builds [path]';
38
- exports.describe = i18n(`${i18nKey}.describe`);
38
+ exports.describe = uiBetaTag(i18n(`${i18nKey}.describe`), false);
39
39
 
40
40
  exports.handler = async options => {
41
41
  await loadAndValidateOptions(options);
@@ -32,7 +32,7 @@ const {
32
32
  // } = require('@hubspot/cli-lib/api/results');
33
33
  const { ensureProjectExists } = require('../../lib/projects');
34
34
  const { loadAndValidateOptions } = require('../../lib/validation');
35
- const { uiLine, uiLink } = require('../../lib/ui');
35
+ const { uiBetaTag, uiLine, uiLink } = require('../../lib/ui');
36
36
  const { projectLogsPrompt } = require('../../lib/prompts/projectsLogsPrompt');
37
37
  // const { tailLogs } = require('../../lib/serverlessLogs');
38
38
  const { i18n } = require('../../lib/lang');
@@ -136,7 +136,7 @@ const getPrivateAppsUrl = accountId => {
136
136
  // };
137
137
 
138
138
  exports.command = 'logs [--project] [--app] [--function] [--endpoint]';
139
- exports.describe = i18n(`${i18nKey}.describe`);
139
+ exports.describe = uiBetaTag(i18n(`${i18nKey}.describe`), false);
140
140
 
141
141
  exports.handler = async options => {
142
142
  await loadAndValidateOptions(options);
@@ -16,12 +16,13 @@ const {
16
16
  ensureProjectExists,
17
17
  } = require('../../lib/projects');
18
18
  const { projectNamePrompt } = require('../../lib/prompts/projectNamePrompt');
19
+ const { uiBetaTag } = require('../../lib/ui');
19
20
  const { EXIT_CODES } = require('../../lib/enums/exitCodes');
20
21
 
21
22
  const i18nKey = 'cli.commands.project.subcommands.open';
22
23
 
23
24
  exports.command = 'open [--project]';
24
- exports.describe = i18n(`${i18nKey}.describe`);
25
+ exports.describe = uiBetaTag(i18n(`${i18nKey}.describe`), false);
25
26
 
26
27
  exports.handler = async options => {
27
28
  await loadAndValidateOptions(options);
@@ -6,7 +6,7 @@ const {
6
6
  } = require('../../lib/commonOpts');
7
7
  const chalk = require('chalk');
8
8
  const { logger } = require('@hubspot/cli-lib/logger');
9
- const { uiLine } = require('../../lib/ui');
9
+ const { uiBetaTag, uiLine } = require('../../lib/ui');
10
10
  const { trackCommandUsage } = require('../../lib/usageTracking');
11
11
  const { loadAndValidateOptions } = require('../../lib/validation');
12
12
  const {
@@ -33,7 +33,7 @@ const { EXIT_CODES } = require('../../lib/enums/exitCodes');
33
33
  const i18nKey = 'cli.commands.project.subcommands.upload';
34
34
 
35
35
  exports.command = 'upload [path]';
36
- exports.describe = i18n(`${i18nKey}.describe`);
36
+ exports.describe = uiBetaTag(i18n(`${i18nKey}.describe`), false);
37
37
 
38
38
  exports.handler = async options => {
39
39
  await loadAndValidateOptions(options);
@@ -13,6 +13,7 @@ const {
13
13
  addUseEnvironmentOptions,
14
14
  } = require('../../lib/commonOpts');
15
15
  const { trackCommandUsage } = require('../../lib/usageTracking');
16
+ const { uiBetaTag } = require('../../lib/ui');
16
17
  const {
17
18
  ensureProjectExists,
18
19
  getProjectConfig,
@@ -34,7 +35,7 @@ const { handleKeypress, handleExit } = require('@hubspot/cli-lib/lib/process');
34
35
  const i18nKey = 'cli.commands.project.subcommands.watch';
35
36
 
36
37
  exports.command = 'watch [path]';
37
- exports.describe = i18n(`${i18nKey}.describe`);
38
+ exports.describe = uiBetaTag(i18n(`${i18nKey}.describe`), false);
38
39
 
39
40
  const handleBuildStatus = async (accountId, projectName, buildId) => {
40
41
  const {
@@ -1,5 +1,6 @@
1
1
  const { addConfigOptions, addAccountOptions } = require('../lib/commonOpts');
2
2
  const { i18n } = require('../lib/lang');
3
+ const { uiBetaTag } = require('../lib/ui');
3
4
  const deploy = require('./project/deploy');
4
5
  const create = require('./project/create');
5
6
  const upload = require('./project/upload');
@@ -14,7 +15,7 @@ const add = require('./project/add');
14
15
  const i18nKey = 'cli.commands.project';
15
16
 
16
17
  exports.command = 'project';
17
- exports.describe = i18n(`${i18nKey}.describe`);
18
+ exports.describe = uiBetaTag(i18n(`${i18nKey}.describe`), false);
18
19
 
19
20
  exports.builder = yargs => {
20
21
  addConfigOptions(yargs, true);
@@ -41,7 +41,7 @@ exports.handler = async options => {
41
41
  secretName,
42
42
  })
43
43
  );
44
- logger.log(i18n(`${i18nKey}.success.updateReupload`));
44
+ logger.log(i18n(`${i18nKey}.success.updateExplanation`));
45
45
  } catch (e) {
46
46
  logger.error(
47
47
  i18n(`${i18nKey}.errors.update`, {
@@ -2,7 +2,7 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const { uploadFolder, hasUploadErrors } = require('@hubspot/cli-lib');
4
4
  const { getFileMapperQueryValues } = require('@hubspot/cli-lib/fileMapper');
5
- const { upload } = require('@hubspot/cli-lib/api/fileMapper');
5
+ const { upload, deleteFile } = require('@hubspot/cli-lib/api/fileMapper');
6
6
  const {
7
7
  getCwd,
8
8
  convertToUnixPath,
@@ -26,6 +26,7 @@ const {
26
26
  getMode,
27
27
  } = require('../lib/commonOpts');
28
28
  const { uploadPrompt } = require('../lib/prompts/uploadPrompt');
29
+ const { cleanUploadPrompt } = require('../lib/prompts/cleanUploadPrompt');
29
30
  const { validateMode, loadAndValidateOptions } = require('../lib/validation');
30
31
  const { trackCommandUsage } = require('../lib/usageTracking');
31
32
  const { getUploadableFileList } = require('../lib/upload');
@@ -204,6 +205,29 @@ exports.handler = async options => {
204
205
  absoluteSrcPath,
205
206
  options.convertFields
206
207
  );
208
+
209
+ if (options.clean) {
210
+ // If clean is true, will first delete the dest folder and then upload src. Cleans up files that only exist on HS.
211
+ let cleanUpload = options.force;
212
+ if (!options.force) {
213
+ cleanUpload = await cleanUploadPrompt(accountId, dest);
214
+ }
215
+ if (cleanUpload) {
216
+ try {
217
+ await deleteFile(accountId, dest);
218
+ logger.log(
219
+ i18n(`${i18nKey}.cleaning`, { accountId, filePath: dest })
220
+ );
221
+ } catch (error) {
222
+ logger.error(
223
+ i18n(`${i18nKey}.errors.deleteFailed`, {
224
+ accountId,
225
+ path: dest,
226
+ })
227
+ );
228
+ }
229
+ }
230
+ }
207
231
  uploadFolder(
208
232
  accountId,
209
233
  absoluteSrcPath,
@@ -276,5 +300,15 @@ exports.builder = yargs => {
276
300
  type: 'boolean',
277
301
  default: false,
278
302
  });
303
+ yargs.option('clean', {
304
+ describe: i18n(`${i18nKey}.options.clean.describe`),
305
+ type: 'boolean',
306
+ default: false,
307
+ });
308
+ yargs.option('force', {
309
+ describe: i18n(`${i18nKey}.options.force.describe`),
310
+ type: 'boolean',
311
+ default: false,
312
+ });
279
313
  return yargs;
280
314
  };
package/lang/en.lyaml CHANGED
@@ -180,7 +180,7 @@ en:
180
180
  customObject:
181
181
  betaMessage: "The Custom Object CLI is currently in beta and is subject to change."
182
182
  describe: "Manage Custom Objects. This feature is currently in beta and the CLI contract is subject to change."
183
- seeMoreLink: "See {{ link }} to find out more."
183
+ seeMoreLink: "View our docs to find out more."
184
184
  subcommands:
185
185
  create:
186
186
  describe: "Create custom object instances"
@@ -456,10 +456,10 @@ en:
456
456
  describe: "Shortcut of the link you'd like to open"
457
457
  selectLink: "Select a link to open"
458
458
  project:
459
- describe: "{{#bold}}[beta]{{/bold}} Commands for working with projects. For more information, visit our documentation: https://developers.hubspot.com/docs/platform/build-and-deploy-using-hubspot-projects"
459
+ describe: "Commands for working with projects. For more information, visit our documentation: https://developers.hubspot.com/docs/platform/build-and-deploy-using-hubspot-projects"
460
460
  subcommands:
461
461
  dev:
462
- describe: "{{#bold}}[beta]{{/bold}} Start local dev for the current project"
462
+ describe: "Start local dev for the current project"
463
463
  logs:
464
464
  betaMessage: "HubSpot projects local development"
465
465
  nonSandboxWarning: "Testing in a sandbox is strongly recommended. To switch the target account, select an option below or run {{#bold}}`hs accounts use`{{/bold}} before running the command again."
@@ -480,7 +480,7 @@ en:
480
480
  examples:
481
481
  default: "Start local dev for the current project"
482
482
  create:
483
- describe: "{{#bold}}[beta]{{/bold}} Create a new project"
483
+ describe: "Create a new project"
484
484
  logs:
485
485
  welcomeMessage: "Welcome to HubSpot Developer Projects!"
486
486
  examples:
@@ -495,7 +495,7 @@ en:
495
495
  templateSource:
496
496
  describe: "Path to custom GitHub repository from which to create project template"
497
497
  add:
498
- describe: "{{#bold}}[beta]{{/bold}} Create a new component within a project"
498
+ describe: "Create a new component within a project"
499
499
  options:
500
500
  name:
501
501
  describe: "Component name"
@@ -510,13 +510,14 @@ en:
510
510
  examples:
511
511
  default: "Create a component within your project"
512
512
  deploy:
513
- describe: "{{#bold}}[beta]{{/bold}} Deploy a project build"
513
+ describe: "Deploy a project build"
514
514
  debug:
515
515
  deploying: "Deploying project at path: {{ path }}"
516
516
  errors:
517
517
  deploy: "Deploy error: {{ details }}"
518
518
  noBuilds: "Deploy error: no builds for this project were found."
519
519
  noBuildId: "You must specify a build to deploy"
520
+ projectNotFound: "{{ projectName }} does not exist in account {{ accountIdentifier }}. Run {{ command }} to upload your project files to HubSpot."
520
521
  examples:
521
522
  default: "Deploy the latest build of the current project"
522
523
  withOptions: "Deploy build 5 of the project my-project"
@@ -526,9 +527,9 @@ en:
526
527
  project:
527
528
  describe: "Project name"
528
529
  listBuilds:
529
- describe: "{{#bold}}[beta]{{/bold}} List the project's builds"
530
+ describe: "List the project's builds"
530
531
  logs:
531
- describe: "{{#bold}}[beta]{{/bold}} Get execution logs for a serverless function within a project"
532
+ describe: "Get execution logs for a serverless function within a project"
532
533
  errors:
533
534
  invalidAppName: "Could not find app with name \"{{ appName }}\" in project \"{{ projectName }}\""
534
535
  logs:
@@ -563,7 +564,7 @@ en:
563
564
  endpoint:
564
565
  describe: "Public endpoint path"
565
566
  upload:
566
- describe: "{{#bold}}[beta]{{/bold}} Upload your project files and create a new build"
567
+ describe: "Upload your project files and create a new build"
567
568
  examples:
568
569
  default: "Upload a project"
569
570
  logs:
@@ -581,7 +582,7 @@ en:
581
582
  path:
582
583
  describe: "Path to a project folder"
583
584
  watch:
584
- describe: "{{#bold}}[beta]{{/bold}} Watch your local project for changes and automatically upload changed files to a new build in HubSpot"
585
+ describe: "Watch your local project for changes and automatically upload changed files to a new build in HubSpot"
585
586
  examples:
586
587
  default: "Watch a project within the myProjectFolder folder"
587
588
  logs:
@@ -593,7 +594,7 @@ en:
593
594
  initialUpload:
594
595
  describe: "Upload directory before watching for updates"
595
596
  download:
596
- describe: "{{#bold}}[beta]{{/bold}} Download your project files from HubSpot and write to a path on your computer"
597
+ describe: "Download your project files from HubSpot and write to a path on your computer"
597
598
  examples:
598
599
  default: "Download the project myProject into myProjectFolder folder"
599
600
  logs:
@@ -612,7 +613,7 @@ en:
612
613
  dest:
613
614
  describe: "Destination folder for the project"
614
615
  open:
615
- describe: "{{#bold}}[beta]{{/bold}} Open the specified project's details page in the browser"
616
+ describe: "Open the specified project's details page in the browser"
616
617
  options:
617
618
  project:
618
619
  describe: "Name of project to open"
@@ -743,7 +744,7 @@ en:
743
744
  describe: "Name of the secret to be updated"
744
745
  success:
745
746
  update: "The secret \"{{ secretName }}\" was updated in the HubSpot account: {{ accountIdentifier }}"
746
- updateReupload: "Make sure to `{{#yellow}}upload{{/yellow}}` all serverless functions using this secret to access its new value."
747
+ updateExplanation: "Existing serverless functions will start using this new value within 10 seconds."
747
748
  theme:
748
749
  describe: "Commands for working with themes, including marketplace validation with the marketplace-validate subcommand."
749
750
  subcommands:
@@ -803,6 +804,7 @@ en:
803
804
  invalidPath: "The path \"{{ path }}\" is not a path to a file or folder"
804
805
  uploadFailed: "Uploading file \"{{ src }}\" to \"{{ dest }}\" failed"
805
806
  someFilesFailed: "One or more files failed to upload to \"{{ dest }}\" in the Design Manager"
807
+ deleteFailed: "Deleting \"{{ path }}\" from account {{ accountId }} failed"
806
808
  options:
807
809
  options:
808
810
  describe: "Options to pass to javascript fields files"
@@ -810,6 +812,10 @@ en:
810
812
  describe: "If true, saves all output from javascript fields files as 'fields.output.json'."
811
813
  convertFields:
812
814
  describe: "If true, converts any javascript fields files contained in module folder or project root."
815
+ clean:
816
+ describe: "Will cause upload to delete files in your HubSpot account that are not found locally."
817
+ force:
818
+ describe: "Skips confirmation prompts when doing a clean upload."
813
819
  previewUrl: "To preview this theme, visit: {{ previewUrl }}"
814
820
  positionals:
815
821
  src:
@@ -821,6 +827,7 @@ en:
821
827
  uploadComplete: "Uploading files to \"{{ dest }}\" in the Design Manager is complete"
822
828
  uploading: "Uploading files from \"{{ src }}\" to \"{{ dest }}\" in the Design Manager of account {{ accountId }}"
823
829
  notUploaded: "There was an error processing \"{{ src }}\". The file has not been uploaded."
830
+ cleaning: "Removing \"{{ filePath }}\" from account {{ accountId }} and uploading local..."
824
831
  watch:
825
832
  describe: "Watch a directory on your computer for changes and upload the changed files to the HubSpot CMS."
826
833
  errors:
@@ -884,6 +891,7 @@ en:
884
891
  stopDev: " * Stop {{ command }}"
885
892
  runUpload: " * Run {{ command }}"
886
893
  restartDev: " * Re-run {{ command }}"
894
+ pushToGithub: " * Commit and push your changes to GitHub"
887
895
  devServer:
888
896
  cleanupError: "Failed to cleanup local dev server: {{ message }}"
889
897
  setupError: "Failed to setup local dev server: {{ message }}"
@@ -959,7 +967,7 @@ en:
959
967
  message: "Run {{ command }} to upload your project to HubSpot and trigger builds"
960
968
  projectDevCommand:
961
969
  command: "hs project dev"
962
- message: "Run {{ command }} to start testing your project locally"
970
+ message: "Run {{ command }} to set up your test environment and start local development"
963
971
  sandboxSyncDevelopmentCommand:
964
972
  command: "hs sandbox sync"
965
973
  message: "Run {{ command }} to to update CRM object definitions in your sandbox"
@@ -988,7 +996,8 @@ en:
988
996
  createNewSandboxOption: "<Test on a new development sandbox>"
989
997
  chooseDefaultAccountOption: "<{{#bold}}\U00002757{{/bold}} Test on this production account {{#bold}}\U00002757{{/bold}}>"
990
998
  promptMessage: "[--account] Choose a sandbox under {{ accountIdentifier }} to test with:"
991
- sandboxLimit: "You’ve reached the limit of {{ limit }} development sandboxes"
999
+ sandboxLimit: "Your account reached the limit of {{ limit }} development sandboxes"
1000
+ sandboxLimitWithSuggestion: "Your account reached the limit of {{ limit }} development sandboxes. Run {{ authCommand }} to add an existing one to the config."
992
1001
  confirmDefaultSandboxAccount: "Continue testing on {{#bold}}{{ accountName }} ({{ accountType }}){{/bold}}? (Y/n)"
993
1002
  projectLogsPrompt:
994
1003
  projectName:
@@ -1062,7 +1071,7 @@ en:
1062
1071
  createProjectPrompt:
1063
1072
  enterName: "[--name] Give your project a name: "
1064
1073
  enterLocation: "[--location] Where should the project be created?"
1065
- selectTemplate: "[--template] Start from a template?"
1074
+ selectTemplate: "[--template] Choose a project template: "
1066
1075
  errors:
1067
1076
  nameRequired: "A project name is required"
1068
1077
  locationRequired: "A project location is required"
@@ -1108,7 +1117,7 @@ en:
1108
1117
  enterName: "[--project] Enter project name:"
1109
1118
  errors:
1110
1119
  invalidName: "You entered an invalid name. Please try again."
1111
- projectDoesNotExist: "Project \"{{ projectName }}\" could not be found in \"{{ accountId }}\""
1120
+ projectDoesNotExist: "Project {{#bold}}{{ projectName }}{{/bold}} could not be found in \"{{ accountIdentifier }}\""
1112
1121
  feedbackPrompt:
1113
1122
  feedbackType:
1114
1123
  message: "What type of feedback would you like to leave?"
@@ -1121,6 +1130,8 @@ en:
1121
1130
  errors:
1122
1131
  buildIdDoesNotExist: "Build {{ buildId }} does not exist for project {{ projectName }}."
1123
1132
  buildAlreadyDeployed: "Build {{ buildId }} is already deployed."
1133
+ cleanUploadPrompt:
1134
+ message: "You are about to remove any remote files in \"{{ filePath }}\" on HubSpot account {{ accountId }} that don't exist locally. Are you sure you want to do this?"
1124
1135
  convertFields:
1125
1136
  positionals:
1126
1137
  src:
@@ -23,7 +23,7 @@ const {
23
23
  UI_COLORS,
24
24
  uiCommandReference,
25
25
  uiAccountDescription,
26
- uiBetaMessage,
26
+ uiBetaTag,
27
27
  uiLink,
28
28
  uiLine,
29
29
  } = require('./ui');
@@ -44,6 +44,7 @@ class LocalDevManager {
44
44
  this.projectDir = options.projectDir;
45
45
  this.debug = options.debug || false;
46
46
  this.deployedBuild = options.deployedBuild;
47
+ this.isGithubLinked = options.isGithubLinked;
47
48
  this.watcher = null;
48
49
  this.uploadWarnings = {};
49
50
 
@@ -100,7 +101,7 @@ class LocalDevManager {
100
101
  console.clear();
101
102
  }
102
103
 
103
- uiBetaMessage(i18n(`${i18nKey}.betaMessage`));
104
+ uiBetaTag(i18n(`${i18nKey}.betaMessage`));
104
105
  logger.log();
105
106
  logger.log(
106
107
  chalk.hex(UI_COLORS.SORBET)(
@@ -188,11 +189,15 @@ class LocalDevManager {
188
189
  command: uiCommandReference('hs project dev'),
189
190
  })
190
191
  );
191
- logger.log(
192
- i18n(`${i18nKey}.uploadWarning.runUpload`, {
193
- command: this.getUploadCommand(),
194
- })
195
- );
192
+ if (this.isGithubLinked) {
193
+ logger.log(i18n(`${i18nKey}.uploadWarning.pushToGithub`));
194
+ } else {
195
+ logger.log(
196
+ i18n(`${i18nKey}.uploadWarning.runUpload`, {
197
+ command: this.getUploadCommand(),
198
+ })
199
+ );
200
+ }
196
201
  logger.log(
197
202
  i18n(`${i18nKey}.uploadWarning.restartDev`, {
198
203
  command: uiCommandReference('hs project dev'),
@@ -0,0 +1,20 @@
1
+ const { promptUser } = require('./promptUtils');
2
+ const { i18n } = require('../lang');
3
+
4
+ const i18nKey = 'cli.lib.prompts.cleanUploadPrompt';
5
+
6
+ const cleanUploadPrompt = async (accountId, filePath) => {
7
+ const promptAnswer = await promptUser([
8
+ {
9
+ name: 'cleanUpload',
10
+ message: i18n(`${i18nKey}.message`, { accountId, filePath }),
11
+ type: 'confirm',
12
+ default: false,
13
+ },
14
+ ]);
15
+ return promptAnswer.cleanUpload;
16
+ };
17
+
18
+ module.exports = {
19
+ cleanUploadPrompt,
20
+ };
@@ -1,6 +1,6 @@
1
1
  const { promptUser } = require('./promptUtils');
2
2
  const { i18n } = require('../lang');
3
- const { uiAccountDescription } = require('../ui');
3
+ const { uiAccountDescription, uiCommandReference } = require('../ui');
4
4
  const { isSandbox, getAccountName } = require('../sandboxes');
5
5
  const { getAccountId } = require('@hubspot/cli-lib');
6
6
  const { getSandboxUsageLimits } = require('@hubspot/cli-lib/sandboxes');
@@ -34,9 +34,16 @@ const selectTargetAccountPrompt = async (accounts, defaultAccountConfig) => {
34
34
  let disabledMessage = false;
35
35
 
36
36
  if (sandboxUsage['DEVELOPER'] && sandboxUsage['DEVELOPER'].available === 0) {
37
- disabledMessage = i18n(`${i18nKey}.sandboxLimit`, {
38
- limit: sandboxUsage['DEVELOPER'].limit,
39
- });
37
+ if (sandboxAccounts.length < sandboxUsage['DEVELOPER'].limit) {
38
+ disabledMessage = i18n(`${i18nKey}.sandboxLimitWithSuggestion`, {
39
+ authCommand: uiCommandReference('hs auth'),
40
+ limit: sandboxUsage['DEVELOPER'].limit,
41
+ });
42
+ } else {
43
+ disabledMessage = i18n(`${i18nKey}.sandboxLimit`, {
44
+ limit: sandboxUsage['DEVELOPER'].limit,
45
+ });
46
+ }
40
47
  }
41
48
 
42
49
  // Order choices by Developer Sandbox -> Standard Sandbox
@@ -1,6 +1,7 @@
1
1
  const { promptUser } = require('./promptUtils');
2
2
  const { i18n } = require('../lang');
3
3
  const { ensureProjectExists } = require('../projects');
4
+ const { uiAccountDescription } = require('../ui');
4
5
 
5
6
  const i18nKey = 'cli.lib.prompts.projectNamePrompt';
6
7
 
@@ -20,7 +21,7 @@ const projectNamePrompt = (accountId, options = {}) => {
20
21
  if (!projectExists) {
21
22
  return i18n(`${i18nKey}.errors.projectDoesNotExist`, {
22
23
  projectName: val,
23
- accountId,
24
+ accountIdentifier: uiAccountDescription(accountId),
24
25
  });
25
26
  }
26
27
  return true;
package/lib/ui.js CHANGED
@@ -1,4 +1,3 @@
1
- const process = require('process');
2
1
  const chalk = require('chalk');
3
2
  const supportsHyperlinks = require('../lib/supportHyperlinks');
4
3
  const supportsColor = require('../lib/supportsColor');
@@ -42,11 +41,13 @@ const getTerminalUISupport = () => {
42
41
  * @param {object} options
43
42
  * @returns {string}
44
43
  */
45
- const uiLink = (linkText, url, { inSpinnies = false } = {}) => {
44
+ const uiLink = (linkText, url) => {
46
45
  const terminalUISupport = getTerminalUISupport();
47
46
  const encodedUrl = encodeURI(url);
47
+
48
48
  if (terminalUISupport.hyperlinks) {
49
49
  const CLOSE_SEQUENCE = '\u001B]8;;\u0007';
50
+
50
51
  const result = [
51
52
  '\u001B]8;;',
52
53
  encodedUrl,
@@ -55,16 +56,7 @@ const uiLink = (linkText, url, { inSpinnies = false } = {}) => {
55
56
  CLOSE_SEQUENCE,
56
57
  ].join('');
57
58
 
58
- // Required b/c spinnies will automatically line-break long lines. "indent" is added to account for indented spinnies
59
- // See https://github.com/jbcarpanelli/spinnies/blob/d672dedcab8c8ce0f6de0bb26ca5582bf602afd7/utils.js#L68-L74
60
- const indent = 5;
61
- const columns =
62
- (process.stderr.columns || 95) - CLOSE_SEQUENCE.length - indent;
63
- const validLength = !inSpinnies || result.length < columns;
64
-
65
- if (validLength) {
66
- return terminalUISupport.color ? chalk.cyan(result) : result;
67
- }
59
+ return terminalUISupport.color ? chalk.cyan(result) : result;
68
60
  }
69
61
 
70
62
  return terminalUISupport.color
@@ -95,7 +87,15 @@ const uiInfoSection = (title, logContent) => {
95
87
  };
96
88
 
97
89
  const uiCommandReference = command => {
98
- return chalk.bold(chalk.hex(UI_COLORS.MARIGOLD_DARK)(`\`${command}\``));
90
+ const terminalUISupport = getTerminalUISupport();
91
+
92
+ const commandReference = `\`${command}\``;
93
+
94
+ return chalk.bold(
95
+ terminalUISupport.color
96
+ ? chalk.hex(UI_COLORS.MARIGOLD_DARK)(commandReference)
97
+ : commandReference
98
+ );
99
99
  };
100
100
 
101
101
  const uiFeatureHighlight = (commands, title) => {
@@ -105,7 +105,7 @@ const uiFeatureHighlight = (commands, title) => {
105
105
  commands.forEach((c, i) => {
106
106
  const commandKey = `${i18nKey}.commandKeys.${c}`;
107
107
  const message = i18n(`${commandKey}.message`, {
108
- command: chalk.bold(i18n(`${commandKey}.command`)),
108
+ command: uiCommandReference(i18n(`${commandKey}.command`)),
109
109
  });
110
110
  if (i !== 0) {
111
111
  logger.log('');
@@ -115,26 +115,28 @@ const uiFeatureHighlight = (commands, title) => {
115
115
  });
116
116
  };
117
117
 
118
- const uiBetaMessage = message => {
118
+ const uiBetaTag = (message, log = true) => {
119
119
  const i18nKey = 'cli.lib.ui';
120
120
 
121
- logger.log(chalk.hex(UI_COLORS.SORBET)(i18n(`${i18nKey}.betaTag`)), message);
122
- };
121
+ const terminalUISupport = getTerminalUISupport();
122
+ const tag = i18n(`${i18nKey}.betaTag`);
123
123
 
124
- const uiBetaWarning = logMessage => {
125
- const i18nKey = 'cli.lib.ui.betaWarning';
124
+ const result = `${
125
+ terminalUISupport.color ? chalk.hex(UI_COLORS.SORBET)(tag) : tag
126
+ } ${message}`;
126
127
 
127
- logger.log(i18n(`${i18nKey}.header`));
128
- logMessage();
129
- logger.log(i18n(`${i18nKey}.footer`));
128
+ if (log) {
129
+ logger.log(result);
130
+ } else {
131
+ return result;
132
+ }
130
133
  };
131
134
 
132
135
  module.exports = {
133
136
  UI_COLORS,
134
137
  uiAccountDescription,
135
138
  uiCommandReference,
136
- uiBetaMessage,
137
- uiBetaWarning,
139
+ uiBetaTag,
138
140
  uiFeatureHighlight,
139
141
  uiInfoSection,
140
142
  uiLine,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubspot/cli",
3
- "version": "4.2.1-beta.4",
3
+ "version": "5.0.1-beta.0",
4
4
  "description": "CLI for working with HubSpot",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -42,5 +42,5 @@
42
42
  "publishConfig": {
43
43
  "access": "public"
44
44
  },
45
- "gitHead": "24d48c93e04bacc5db761cc15489b5bc82e17847"
45
+ "gitHead": "50781b4dba44aef14d5357a25692e46689141aa3"
46
46
  }