@hubspot/cli 7.4.5-beta.0 → 7.4.6-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.
Files changed (50) hide show
  1. package/commands/app/migrate.d.ts +3 -3
  2. package/commands/app/migrate.js +8 -6
  3. package/commands/app.js +0 -2
  4. package/commands/project/add.d.ts +3 -7
  5. package/commands/project/add.js +10 -9
  6. package/commands/project/cloneApp.d.ts +2 -8
  7. package/commands/project/cloneApp.js +25 -26
  8. package/commands/project/create.d.ts +10 -1
  9. package/commands/project/create.js +80 -62
  10. package/commands/project/deploy.d.ts +3 -6
  11. package/commands/project/deploy.js +9 -9
  12. package/commands/project/dev/index.d.ts +4 -2
  13. package/commands/project/dev/index.js +16 -7
  14. package/commands/project/download.d.ts +3 -7
  15. package/commands/project/download.js +9 -9
  16. package/commands/project/installDeps.d.ts +3 -6
  17. package/commands/project/installDeps.js +10 -9
  18. package/commands/project/listBuilds.d.ts +3 -7
  19. package/commands/project/listBuilds.js +15 -14
  20. package/commands/project/logs.d.ts +3 -6
  21. package/commands/project/logs.js +11 -12
  22. package/commands/project/migrate.d.ts +3 -8
  23. package/commands/project/migrate.js +17 -18
  24. package/commands/project/migrateApp.d.ts +2 -7
  25. package/commands/project/migrateApp.js +18 -18
  26. package/commands/project/open.d.ts +3 -7
  27. package/commands/project/open.js +15 -14
  28. package/commands/project/upload.d.ts +3 -7
  29. package/commands/project/upload.js +9 -9
  30. package/commands/project/watch.d.ts +6 -1
  31. package/commands/project/watch.js +82 -71
  32. package/commands/project.d.ts +3 -1
  33. package/commands/project.js +47 -36
  34. package/lang/en.d.ts +4 -0
  35. package/lang/en.js +4 -0
  36. package/lang/en.lyaml +4 -0
  37. package/lib/app/migrate.js +30 -12
  38. package/lib/commonOpts.d.ts +1 -1
  39. package/lib/commonOpts.js +27 -8
  40. package/lib/middleware/configMiddleware.js +2 -2
  41. package/lib/projects/upload.d.ts +1 -1
  42. package/lib/projects/upload.js +1 -1
  43. package/lib/projects/watch.d.ts +1 -1
  44. package/lib/prompts/createProjectPrompt.d.ts +11 -4
  45. package/lib/prompts/createProjectPrompt.js +6 -0
  46. package/lib/ui/index.d.ts +3 -2
  47. package/lib/ui/index.js +1 -0
  48. package/lib/yargsUtils.d.ts +1 -1
  49. package/package.json +1 -1
  50. package/types/Yargs.d.ts +5 -1
@@ -1,105 +1,106 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- // @ts-nocheck
4
- const { uiLink } = require('../../lib/ui');
5
- const { useV3Api } = require('../../lib/projects/buildAndDeploy');
6
- const { uiCommandReference } = require('../../lib/ui');
7
- const { i18n } = require('../../lib/lang');
8
- const { createWatcher } = require('../../lib/projects/watch');
9
- const { logError, ApiErrorContext } = require('../../lib/errorHandlers/index');
10
- const { logger } = require('@hubspot/local-dev-lib/logger');
11
- const { PROJECT_ERROR_TYPES } = require('../../lib/constants');
12
- const { addAccountOptions, addConfigOptions, addUseEnvironmentOptions, } = require('../../lib/commonOpts');
13
- const { trackCommandUsage } = require('../../lib/usageTracking');
14
- const { uiBetaTag } = require('../../lib/ui');
15
- const { getProjectConfig, validateProjectConfig, } = require('../../lib/projects/config');
16
- const { ensureProjectExists, } = require('../../lib/projects/ensureProjectExists');
17
- const { logFeedbackMessage } = require('../../lib/projects/ui');
18
- const { handleProjectUpload } = require('../../lib/projects/upload');
19
- const { pollBuildStatus, pollDeployStatus, } = require('../../lib/projects/buildAndDeploy');
20
- const { cancelStagedBuild, fetchProjectBuilds, } = require('@hubspot/local-dev-lib/api/projects');
21
- const { isSpecifiedError } = require('@hubspot/local-dev-lib/errors/index');
22
- const { EXIT_CODES } = require('../../lib/enums/exitCodes');
23
- const { handleKeypress, handleExit } = require('../../lib/process');
24
- exports.command = 'watch';
25
- exports.describe = uiBetaTag(i18n(`commands.project.subcommands.watch.describe`), false);
26
- const handleBuildStatus = async (accountId, projectName, buildId) => {
27
- const { isAutoDeployEnabled, deployStatusTaskLocator } = await pollBuildStatus(accountId, projectName, buildId);
3
+ const projects_1 = require("@hubspot/local-dev-lib/api/projects");
4
+ const index_1 = require("@hubspot/local-dev-lib/errors/index");
5
+ const buildAndDeploy_1 = require("../../lib/projects/buildAndDeploy");
6
+ const ui_1 = require("../../lib/ui");
7
+ const lang_1 = require("../../lib/lang");
8
+ const watch_1 = require("../../lib/projects/watch");
9
+ const index_2 = require("../../lib/errorHandlers/index");
10
+ const logger_1 = require("@hubspot/local-dev-lib/logger");
11
+ const constants_1 = require("../../lib/constants");
12
+ const usageTracking_1 = require("../../lib/usageTracking");
13
+ const config_1 = require("../../lib/projects/config");
14
+ const ui_2 = require("../../lib/projects/ui");
15
+ const ensureProjectExists_1 = require("../../lib/projects/ensureProjectExists");
16
+ const upload_1 = require("../../lib/projects/upload");
17
+ const buildAndDeploy_2 = require("../../lib/projects/buildAndDeploy");
18
+ const exitCodes_1 = require("../../lib/enums/exitCodes");
19
+ const process_1 = require("../../lib/process");
20
+ const yargsUtils_1 = require("../../lib/yargsUtils");
21
+ const command = 'watch';
22
+ const describe = (0, ui_1.uiBetaTag)((0, lang_1.i18n)(`commands.project.subcommands.watch.describe`), false);
23
+ async function handleBuildStatus(accountId, projectName, buildId) {
24
+ const { isAutoDeployEnabled, deployStatusTaskLocator } = await (0, buildAndDeploy_2.pollBuildStatus)(accountId, projectName, buildId, null);
28
25
  if (isAutoDeployEnabled && deployStatusTaskLocator) {
29
- await pollDeployStatus(accountId, projectName, deployStatusTaskLocator.id, buildId);
26
+ await (0, buildAndDeploy_2.pollDeployStatus)(accountId, projectName, Number(deployStatusTaskLocator.id), buildId);
30
27
  }
31
- logFeedbackMessage(buildId);
32
- };
33
- const handleUserInput = (accountId, projectName, currentBuildId) => {
28
+ (0, ui_2.logFeedbackMessage)(buildId);
29
+ }
30
+ function handleUserInput(accountId, projectName, currentBuildId) {
34
31
  const onTerminate = async () => {
35
- logger.log(i18n(`commands.project.subcommands.watch.logs.processExited`));
32
+ logger_1.logger.log((0, lang_1.i18n)(`commands.project.subcommands.watch.logs.processExited`));
36
33
  if (currentBuildId) {
37
34
  try {
38
- await cancelStagedBuild(accountId, projectName);
39
- process.exit(EXIT_CODES.SUCCESS);
35
+ await (0, projects_1.cancelStagedBuild)(accountId, projectName);
36
+ process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
40
37
  }
41
38
  catch (err) {
42
- if (isSpecifiedError(err, {
43
- subCategory: PROJECT_ERROR_TYPES.BUILD_NOT_IN_PROGRESS,
39
+ if ((0, index_1.isSpecifiedError)(err, {
40
+ subCategory: constants_1.PROJECT_ERROR_TYPES.BUILD_NOT_IN_PROGRESS,
44
41
  })) {
45
- process.exit(EXIT_CODES.SUCCESS);
42
+ process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
46
43
  }
47
44
  else {
48
- logError(err, new ApiErrorContext({ accountId }));
49
- process.exit(EXIT_CODES.ERROR);
45
+ (0, index_2.logError)(err, new index_2.ApiErrorContext({ accountId }));
46
+ process.exit(exitCodes_1.EXIT_CODES.ERROR);
50
47
  }
51
48
  }
52
49
  }
53
50
  else {
54
- process.exit(EXIT_CODES.SUCCESS);
51
+ process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
55
52
  }
56
53
  };
57
- handleExit(onTerminate);
58
- handleKeypress(key => {
54
+ (0, process_1.handleExit)(onTerminate);
55
+ (0, process_1.handleKeypress)(key => {
59
56
  if ((key.ctrl && key.name === 'c') || key.name === 'q') {
60
57
  onTerminate();
61
58
  }
62
59
  });
63
- };
64
- exports.handler = async (options) => {
65
- const { initialUpload, derivedAccountId } = options;
66
- trackCommandUsage('project-watch', null, derivedAccountId);
67
- const { projectConfig, projectDir } = await getProjectConfig();
68
- if (useV3Api(projectConfig?.platformVersion)) {
69
- logger.error(i18n(`commands.project.subcommands.watch.errors.v3ApiError`, {
70
- command: uiCommandReference('hs project watch'),
71
- newCommand: uiCommandReference('hs project dev'),
60
+ }
61
+ async function handler(args) {
62
+ const { initialUpload, derivedAccountId } = args;
63
+ (0, usageTracking_1.trackCommandUsage)('project-watch', undefined, derivedAccountId);
64
+ const { projectConfig, projectDir } = await (0, config_1.getProjectConfig)();
65
+ (0, config_1.validateProjectConfig)(projectConfig, projectDir);
66
+ if (!projectConfig || !projectDir) {
67
+ logger_1.logger.error((0, lang_1.i18n)(`commands.project.subcommands.watch.errors.projectConfigNotFound`));
68
+ return process.exit(exitCodes_1.EXIT_CODES.ERROR);
69
+ }
70
+ if ((0, buildAndDeploy_1.useV3Api)(projectConfig.platformVersion)) {
71
+ logger_1.logger.error((0, lang_1.i18n)(`commands.project.subcommands.watch.errors.v3ApiError`, {
72
+ command: (0, ui_1.uiCommandReference)('hs project watch'),
73
+ newCommand: (0, ui_1.uiCommandReference)('hs project dev'),
72
74
  platformVersion: projectConfig.platformVersion,
73
- linkToDocs: uiLink('How to develop locally.', 'https://developers.hubspot.com/docs/guides/crm/ui-extensions/local-development'),
75
+ linkToDocs: (0, ui_1.uiLink)('How to develop locally.', 'https://developers.hubspot.com/docs/guides/crm/ui-extensions/local-development'),
74
76
  }));
75
- return process.exit(EXIT_CODES.ERROR);
77
+ return process.exit(exitCodes_1.EXIT_CODES.ERROR);
76
78
  }
77
- validateProjectConfig(projectConfig, projectDir);
78
- await ensureProjectExists(derivedAccountId, projectConfig.name);
79
+ await (0, ensureProjectExists_1.ensureProjectExists)(derivedAccountId, projectConfig.name);
79
80
  try {
80
- const { data: { results: builds }, } = await fetchProjectBuilds(derivedAccountId, projectConfig.name, options);
81
+ const { data: { results: builds }, } = await (0, projects_1.fetchProjectBuilds)(derivedAccountId, projectConfig.name);
81
82
  const hasNoBuilds = !builds || !builds.length;
82
83
  const startWatching = async () => {
83
- await createWatcher(derivedAccountId, projectConfig, projectDir, handleBuildStatus, handleUserInput);
84
+ await (0, watch_1.createWatcher)(derivedAccountId, projectConfig, projectDir, handleBuildStatus, handleUserInput);
84
85
  };
85
86
  // Upload all files if no build exists for this project yet
86
87
  if (initialUpload || hasNoBuilds) {
87
- const { uploadError } = await handleProjectUpload(derivedAccountId, projectConfig, projectDir, startWatching);
88
+ const { uploadError } = await (0, upload_1.handleProjectUpload)(derivedAccountId, projectConfig, projectDir, startWatching);
88
89
  if (uploadError) {
89
- if (isSpecifiedError(uploadError, {
90
- subCategory: PROJECT_ERROR_TYPES.PROJECT_LOCKED,
90
+ if ((0, index_1.isSpecifiedError)(uploadError, {
91
+ subCategory: constants_1.PROJECT_ERROR_TYPES.PROJECT_LOCKED,
91
92
  })) {
92
- logger.log();
93
- logger.error(i18n(`commands.project.subcommands.watch.errors.projectLockedError`));
94
- logger.log();
93
+ logger_1.logger.log();
94
+ logger_1.logger.error((0, lang_1.i18n)(`commands.project.subcommands.watch.errors.projectLockedError`));
95
+ logger_1.logger.log();
95
96
  }
96
97
  else {
97
- logError(uploadError, new ApiErrorContext({
98
+ (0, index_2.logError)(uploadError, new index_2.ApiErrorContext({
98
99
  accountId: derivedAccountId,
99
100
  request: 'project upload',
100
101
  }));
101
102
  }
102
- process.exit(EXIT_CODES.ERROR);
103
+ process.exit(exitCodes_1.EXIT_CODES.ERROR);
103
104
  }
104
105
  }
105
106
  else {
@@ -107,23 +108,33 @@ exports.handler = async (options) => {
107
108
  }
108
109
  }
109
110
  catch (e) {
110
- logError(e, new ApiErrorContext({ accountId: derivedAccountId }));
111
+ (0, index_2.logError)(e, new index_2.ApiErrorContext({ accountId: derivedAccountId }));
111
112
  }
112
- };
113
- exports.builder = yargs => {
113
+ }
114
+ function projectWatchBuilder(yargs) {
114
115
  yargs.option('initial-upload', {
115
116
  alias: 'i',
116
- describe: i18n(`commands.project.subcommands.watch.options.initialUpload.describe`),
117
+ describe: (0, lang_1.i18n)(`commands.project.subcommands.watch.options.initialUpload.describe`),
117
118
  type: 'boolean',
118
119
  });
119
120
  yargs.example([
120
121
  [
121
122
  '$0 project watch',
122
- i18n(`commands.project.subcommands.watch.examples.default`),
123
+ (0, lang_1.i18n)(`commands.project.subcommands.watch.examples.default`),
123
124
  ],
124
125
  ]);
125
- addConfigOptions(yargs);
126
- addAccountOptions(yargs);
127
- addUseEnvironmentOptions(yargs);
128
126
  return yargs;
127
+ }
128
+ const builder = (0, yargsUtils_1.makeYargsBuilder)(projectWatchBuilder, command, describe, {
129
+ useGlobalOptions: true,
130
+ useAccountOptions: true,
131
+ useConfigOptions: true,
132
+ useEnvironmentOptions: true,
133
+ });
134
+ const projectWatchCommand = {
135
+ command,
136
+ describe,
137
+ handler,
138
+ builder,
129
139
  };
140
+ exports.default = projectWatchCommand;
@@ -1 +1,3 @@
1
- export {};
1
+ import { YargsCommandModuleBucket } from '../types/Yargs';
2
+ declare const projectCommand: YargsCommandModuleBucket;
3
+ export default projectCommand;
@@ -1,42 +1,53 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
- // @ts-nocheck
4
- const { addGlobalOptions } = require('../lib/commonOpts');
5
- const { i18n } = require('../lib/lang');
6
- const { uiBetaTag } = require('../lib/ui');
7
- const deploy = require('./project/deploy');
8
- const create = require('./project/create');
9
- const upload = require('./project/upload');
10
- const listBuilds = require('./project/listBuilds');
11
- const logs = require('./project/logs');
12
- const watch = require('./project/watch');
13
- const download = require('./project/download');
14
- const open = require('./project/open');
15
- const dev = require('./project/dev');
16
- const add = require('./project/add');
17
- const migrateApp = require('./project/migrateApp');
18
- const migrate = require('./project/migrate');
19
- const cloneApp = require('./project/cloneApp');
20
- const installDeps = require('./project/installDeps');
21
- exports.command = ['project', 'projects'];
22
- exports.describe = uiBetaTag(i18n(`commands.project.describe`), false);
23
- exports.builder = yargs => {
24
- addGlobalOptions(yargs);
6
+ const lang_1 = require("../lib/lang");
7
+ const ui_1 = require("../lib/ui");
8
+ const deploy_1 = __importDefault(require("./project/deploy"));
9
+ const create_1 = __importDefault(require("./project/create"));
10
+ const upload_1 = __importDefault(require("./project/upload"));
11
+ const listBuilds_1 = __importDefault(require("./project/listBuilds"));
12
+ const logs_1 = __importDefault(require("./project/logs"));
13
+ const watch_1 = __importDefault(require("./project/watch"));
14
+ const download_1 = __importDefault(require("./project/download"));
15
+ const open_1 = __importDefault(require("./project/open"));
16
+ const dev_1 = __importDefault(require("./project/dev"));
17
+ const add_1 = __importDefault(require("./project/add"));
18
+ const migrate_1 = __importDefault(require("./project/migrate"));
19
+ const migrateApp_1 = __importDefault(require("./project/migrateApp"));
20
+ const cloneApp_1 = __importDefault(require("./project/cloneApp"));
21
+ const installDeps_1 = __importDefault(require("./project/installDeps"));
22
+ const yargsUtils_1 = require("../lib/yargsUtils");
23
+ const command = ['project', 'projects'];
24
+ const describe = (0, ui_1.uiBetaTag)((0, lang_1.i18n)(`commands.project.describe`), false);
25
+ function projectBuilder(yargs) {
25
26
  yargs
26
- .command(create)
27
- .command(add)
28
- .command(watch)
29
- .command(dev)
30
- .command(upload)
31
- .command(deploy)
32
- .command(logs)
33
- .command(listBuilds)
34
- .command(download)
35
- .command(open)
36
- .command(migrateApp)
37
- .command(migrate)
38
- .command(cloneApp)
39
- .command(installDeps)
27
+ .command(create_1.default)
28
+ .command(add_1.default)
29
+ .command(watch_1.default)
30
+ .command(dev_1.default)
31
+ .command(upload_1.default)
32
+ .command(deploy_1.default)
33
+ .command(logs_1.default)
34
+ .command(listBuilds_1.default)
35
+ .command(download_1.default)
36
+ .command(open_1.default)
37
+ .command(migrateApp_1.default)
38
+ .command(migrate_1.default)
39
+ .command(cloneApp_1.default)
40
+ .command(installDeps_1.default)
40
41
  .demandCommand(1, '');
41
42
  return yargs;
43
+ }
44
+ const builder = (0, yargsUtils_1.makeYargsBuilder)(projectBuilder, command, describe);
45
+ const projectCommand = {
46
+ command,
47
+ describe,
48
+ builder,
49
+ handler: () => { },
42
50
  };
51
+ exports.default = projectCommand;
52
+ // TODO Remove this legacy export once we've migrated all commands to TS
53
+ module.exports = projectCommand;
package/lang/en.d.ts CHANGED
@@ -768,6 +768,7 @@ export declare const commands: {
768
768
  readonly describe: "Create a new project.";
769
769
  readonly errors: {
770
770
  readonly failedToDownloadProject: "Failed to download project. Please try again later.";
771
+ readonly invalidTemplateSource: "Invalid template source provided. Use the format <Owner>/<Repo> and try again.";
771
772
  readonly failedToFetchProjectList: "Failed to fetch the list of available project templates. Please try again later.";
772
773
  readonly cannotNestProjects: (projectDir: string | number) => string;
773
774
  };
@@ -1043,6 +1044,8 @@ export declare const commands: {
1043
1044
  readonly fileAlreadyQueued: (filePath: string | number) => string;
1044
1045
  };
1045
1046
  readonly errors: {
1047
+ readonly projectConfigNotFound: "No project config found. Please ensure that you are in a project directory.";
1048
+ readonly projectLockedError: `Your project is locked. This may mean that another user is running the ${string} command for this project. If this is you, unlock the project in Projects UI.`;
1046
1049
  readonly uploadFailed: (remotePath: string | number, filePath: string | number) => string;
1047
1050
  readonly deleteFileFailed: (remotePath: string | number) => string;
1048
1051
  readonly deleteFolderFailed: (remotePath: string | number) => string;
@@ -2457,6 +2460,7 @@ export declare const lib: {
2457
2460
  readonly invalidDest: "There is an existing project at this destination. Please provide a new path for this project.";
2458
2461
  readonly invalidCharacters: "The selected destination contains invalid characters. Please provide a new path and try again.";
2459
2462
  readonly invalidTemplate: (template: string | number) => string;
2463
+ readonly projectTemplateRequired: "Project template is required when projectTemplates is provided";
2460
2464
  };
2461
2465
  };
2462
2466
  readonly selectPublicAppPrompt: {
package/lang/en.js CHANGED
@@ -778,6 +778,7 @@ exports.commands = {
778
778
  describe: 'Create a new project.',
779
779
  errors: {
780
780
  failedToDownloadProject: 'Failed to download project. Please try again later.',
781
+ invalidTemplateSource: 'Invalid template source provided. Use the format <Owner>/<Repo> and try again.',
781
782
  failedToFetchProjectList: 'Failed to fetch the list of available project templates. Please try again later.',
782
783
  cannotNestProjects: projectDir => `A project already exists at ${projectDir}. Projects cannot be nested within other projects. Please choose a different destination and try again.`,
783
784
  },
@@ -1051,6 +1052,8 @@ exports.commands = {
1051
1052
  fileAlreadyQueued: filePath => `File "${filePath}" is already queued for upload`,
1052
1053
  },
1053
1054
  errors: {
1055
+ projectConfigNotFound: 'No project config found. Please ensure that you are in a project directory.',
1056
+ projectLockedError: `Your project is locked. This may mean that another user is running the ${chalk_1.default.bold(`hs project dev`)} command for this project. If this is you, unlock the project in Projects UI.`,
1054
1057
  uploadFailed: (remotePath, filePath) => `Failed to upload file "${filePath}" to "${remotePath}"`,
1055
1058
  deleteFileFailed: remotePath => `Failed to delete file "${remotePath}"`,
1056
1059
  deleteFolderFailed: remotePath => `Failed to delete folder "${remotePath}"`,
@@ -2465,6 +2468,7 @@ exports.lib = {
2465
2468
  invalidDest: 'There is an existing project at this destination. Please provide a new path for this project.',
2466
2469
  invalidCharacters: 'The selected destination contains invalid characters. Please provide a new path and try again.',
2467
2470
  invalidTemplate: template => `[--template] Could not find template "${template}". Please choose an available template:`,
2471
+ projectTemplateRequired: 'Project template is required when projectTemplates is provided',
2468
2472
  },
2469
2473
  },
2470
2474
  selectPublicAppPrompt: {
package/lang/en.lyaml CHANGED
@@ -601,6 +601,7 @@ en:
601
601
  describe: "Create a new project."
602
602
  errors:
603
603
  failedToDownloadProject: "Failed to download project. Please try again later."
604
+ invalidTemplateSource: "Invalid template source provided. Use the format <Owner>/<Repo> and try again."
604
605
  failedToFetchProjectList: "Failed to fetch the list of available project templates. Please try again later."
605
606
  cannotNestProjects: "A project already exists at {{ projectDir }}. Projects cannot be nested within other projects. Please choose a different destination and try again."
606
607
  logs:
@@ -806,6 +807,8 @@ en:
806
807
  attemptNewBuild: "Attempting to create a new build"
807
808
  fileAlreadyQueued: "File \"{{ filePath }}\" is already queued for upload"
808
809
  errors:
810
+ projectConfigNotFound: "No project config found. Please ensure that you are in a project directory."
811
+ projectLockedError: "Your project is locked. This may mean that another user is running the {{#bold}}`hs project dev`{{/bold}} command for this project. If this is you, unlock the project in Projects UI."
809
812
  uploadFailed: "Failed to upload file \"{{ filePath }}\" to \"{{ remotePath }}\""
810
813
  deleteFileFailed: "Failed to delete file \"{{ remotePath }}\""
811
814
  deleteFolderFailed: "Failed to delete folder \"{{ remotePath }}\""
@@ -1422,6 +1425,7 @@ en:
1422
1425
  invalidDest: "There is an existing project at this destination. Please provide a new path for this project."
1423
1426
  invalidCharacters: "The selected destination contains invalid characters. Please provide a new path and try again."
1424
1427
  invalidTemplate: "[--template] Could not find template \"{{ template }}\". Please choose an available template:"
1428
+ projectTemplateRequired: "Project template is required when projectTemplates is provided"
1425
1429
  selectPublicAppPrompt:
1426
1430
  selectAppIdMigrate: "[--appId] Choose an app under {{ accountName }} to migrate:"
1427
1431
  selectAppIdClone: "[--appId] Choose an app under {{ accountName }} to clone:"
@@ -51,6 +51,18 @@ function filterAppsByProjectName(projectConfig) {
51
51
  return true;
52
52
  };
53
53
  }
54
+ function buildErrorMessageFromMigrationStatus(error) {
55
+ const { componentErrors, projectErrorDetail } = error;
56
+ if (!componentErrors || !componentErrors.length) {
57
+ return projectErrorDetail;
58
+ }
59
+ return `${projectErrorDetail}: \n\t- ${componentErrors
60
+ .map(componentError => {
61
+ const { componentType, errorMessage, developerSymbol: uid, } = componentError;
62
+ return `${componentType}${uid ? ` (${uid})` : ''}: ${errorMessage}`;
63
+ })
64
+ .join('\n\t- ')}`;
65
+ }
54
66
  async function fetchMigrationApps(appId, derivedAccountId, platformVersion, projectConfig) {
55
67
  const { data: { migratableApps, unmigratableApps }, } = await (0, migrate_1.listAppsForMigration)(derivedAccountId, platformVersion);
56
68
  const filteredMigratableApps = migratableApps.filter(filterAppsByProjectName(projectConfig));
@@ -186,7 +198,23 @@ async function beginMigration(derivedAccountId, appId, platformVersion) {
186
198
  const uidMap = {};
187
199
  const { data } = await (0, migrate_1.initializeMigration)(derivedAccountId, appId, platformVersion);
188
200
  const { migrationId } = data;
189
- const pollResponse = await pollMigrationStatus(derivedAccountId, migrationId, [Migration_1.MIGRATION_STATUS.INPUT_REQUIRED]);
201
+ let pollResponse;
202
+ try {
203
+ pollResponse = await pollMigrationStatus(derivedAccountId, migrationId, [
204
+ Migration_1.MIGRATION_STATUS.INPUT_REQUIRED,
205
+ ]);
206
+ }
207
+ catch (error) {
208
+ SpinniesManager_1.default.fail('beginningMigration', {
209
+ text: en_1.lib.migrate.spinners.unableToStartMigration,
210
+ });
211
+ if ((0, migrate_1.isMigrationStatus)(error) && error.status === Migration_1.MIGRATION_STATUS.FAILURE) {
212
+ throw new Error(buildErrorMessageFromMigrationStatus(error));
213
+ }
214
+ throw new Error(en_1.lib.migrate.errors.migrationFailed, {
215
+ cause: error,
216
+ });
217
+ }
190
218
  if (pollResponse.status !== Migration_1.MIGRATION_STATUS.INPUT_REQUIRED) {
191
219
  SpinniesManager_1.default.fail('beginningMigration', {
192
220
  text: en_1.lib.migrate.spinners.unableToStartMigration,
@@ -235,17 +263,7 @@ async function finalizeMigration(derivedAccountId, migrationId, uidMap, projectN
235
263
  text: en_1.lib.migrate.spinners.migrationFailed,
236
264
  });
237
265
  if ((0, migrate_1.isMigrationStatus)(error) && error.status === Migration_1.MIGRATION_STATUS.FAILURE) {
238
- const { componentErrors, projectErrorDetail } = error;
239
- if (!componentErrors || !componentErrors.length) {
240
- throw new Error(projectErrorDetail);
241
- }
242
- const errorMessage = `${projectErrorDetail}: \n\t- ${componentErrors
243
- .map(componentError => {
244
- const { componentType, errorMessage, developerSymbol: uid, } = componentError;
245
- return `${componentType}${uid ? ` (${uid})` : ''}: ${errorMessage}`;
246
- })
247
- .join('\n\t- ')}`;
248
- throw new Error(errorMessage);
266
+ throw new Error(buildErrorMessageFromMigrationStatus(error));
249
267
  }
250
268
  throw new Error(en_1.lib.migrate.errors.migrationFailed, {
251
269
  cause: error,
@@ -11,7 +11,7 @@ export declare function addCmsPublishModeOptions(yargs: Argv, { read, write }: {
11
11
  }): Argv;
12
12
  export declare function addTestingOptions(yargs: Argv): Argv;
13
13
  export declare function addUseEnvironmentOptions(yargs: Argv): Argv;
14
- export declare function addCustomHelpOutput(yargs: Argv, command: string, describe: string): Promise<void>;
14
+ export declare function addCustomHelpOutput(yargs: Argv, command: string | string[], describe?: string): Promise<void>;
15
15
  export declare function setLogLevel(options: Arguments<{
16
16
  debug?: boolean;
17
17
  networkDebug?: boolean;
package/lib/commonOpts.js CHANGED
@@ -78,26 +78,45 @@ function addTestingOptions(yargs) {
78
78
  });
79
79
  }
80
80
  function addUseEnvironmentOptions(yargs) {
81
- return yargs
82
- .option('use-env', {
81
+ yargs.option('use-env', {
83
82
  describe: (0, lang_1.i18n)(`${i18nKey}.options.useEnv.describe`),
84
83
  type: 'boolean',
85
- })
86
- .conflicts('use-env', 'account');
84
+ });
85
+ yargs.conflicts('use-env', 'account');
86
+ return yargs;
87
87
  }
88
88
  async function addCustomHelpOutput(yargs, command, describe) {
89
89
  try {
90
90
  const parsedArgv = (0, yargs_parser_1.default)(process.argv.slice(2));
91
91
  if (parsedArgv && parsedArgv.help) {
92
- // Construct the full command, including positional arguments
93
92
  const commandBase = `hs ${parsedArgv._.slice(0, -1).join(' ')}`;
94
- const fullCommand = `${commandBase.trim()} ${command}`;
93
+ // Make sure we are targeting the correct command by confirming that
94
+ // "command" matches the last part of the user's input command
95
+ const checkIsTargetCommand = (command) => {
96
+ const targetBaseCommand = command.split(' ')[0];
97
+ return targetBaseCommand === parsedArgv._[parsedArgv._.length - 1];
98
+ };
99
+ const isTargetedCommand = Array.isArray(command)
100
+ ? command.some(checkIsTargetCommand)
101
+ : checkIsTargetCommand(command);
102
+ if (!isTargetedCommand) {
103
+ return;
104
+ }
105
+ // Construct the full command, including positional arguments
106
+ const commandString = Array.isArray(command) ? command[0] : command;
107
+ const fullCommand = `${commandBase.trim()} ${commandString}`;
95
108
  // Format the original help output to be more readable
96
109
  let commandHelp = await yargs.getHelp();
97
- ['Options:', 'Examples:', 'Positionals:'].forEach(header => {
110
+ ['Options:', 'Commands:', 'Examples:', 'Positionals:'].forEach(header => {
98
111
  commandHelp = commandHelp.replace(header, chalk_1.default.bold(header));
99
112
  });
100
- logger_1.logger.log(`${(0, ui_1.uiCommandReference)(fullCommand, false)}\n\n${describe}\n\n${commandHelp}`);
113
+ // Remove "hs <command>" from the help output (this shows up for command buckets)
114
+ commandHelp = commandHelp.replace('hs <command>\n', '');
115
+ // Remove the first line of the help output if it's empty
116
+ if (commandHelp.startsWith('\n')) {
117
+ commandHelp = commandHelp.slice(1);
118
+ }
119
+ logger_1.logger.log(`${(0, ui_1.uiCommandReference)(fullCommand, false)}\n\n${describe ? `${describe}\n\n` : ''}${commandHelp}`);
101
120
  process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
102
121
  }
103
122
  }
@@ -43,7 +43,7 @@ const SKIP_CONFIG_VALIDATION = {
43
43
  };
44
44
  async function loadConfigMiddleware(argv) {
45
45
  // Skip this when no command is provided
46
- if (!argv._.length) {
46
+ if (!argv._.length || argv.help) {
47
47
  return;
48
48
  }
49
49
  const maybeValidateConfig = () => {
@@ -104,7 +104,7 @@ const SKIP_ACCOUNT_VALIDATION = {
104
104
  };
105
105
  async function validateAccountOptions(argv) {
106
106
  // Skip this when no command is provided
107
- if (argv._.length) {
107
+ if (argv._.length && !argv.help) {
108
108
  let validAccount = true;
109
109
  if (!(0, utils_1.isTargetedCommand)(argv._, SKIP_ACCOUNT_VALIDATION)) {
110
110
  validAccount = await (0, validation_1.validateAccount)(argv);
@@ -5,5 +5,5 @@ type ProjectUploadResult<T> = {
5
5
  result?: T;
6
6
  uploadError?: unknown;
7
7
  };
8
- export declare function handleProjectUpload<T>(accountId: number, projectConfig: ProjectConfig, projectDir: string, callbackFunc: ProjectUploadCallbackFunction<T>, uploadMessage: string, sendIR?: boolean, skipValidation?: boolean): Promise<ProjectUploadResult<T>>;
8
+ export declare function handleProjectUpload<T>(accountId: number, projectConfig: ProjectConfig, projectDir: string, callbackFunc: ProjectUploadCallbackFunction<T>, uploadMessage?: string, sendIR?: boolean, skipValidation?: boolean): Promise<ProjectUploadResult<T>>;
9
9
  export {};
@@ -45,7 +45,7 @@ async function uploadProjectFiles(accountId, projectName, filePath, uploadMessag
45
45
  }
46
46
  return { buildId, error };
47
47
  }
48
- async function handleProjectUpload(accountId, projectConfig, projectDir, callbackFunc, uploadMessage, sendIR = false, skipValidation = false) {
48
+ async function handleProjectUpload(accountId, projectConfig, projectDir, callbackFunc, uploadMessage = '', sendIR = false, skipValidation = false) {
49
49
  const srcDir = path_1.default.resolve(projectDir, projectConfig.srcDir);
50
50
  const filenames = fs_extra_1.default.readdirSync(srcDir);
51
51
  if (!filenames || filenames.length === 0) {
@@ -1,4 +1,4 @@
1
1
  import { ProjectConfig } from '../../types/Projects';
2
- type ProjectWatchHandlerFunction = (accountId: number, projectName: string, currentBuildId: number) => Promise<void>;
2
+ type ProjectWatchHandlerFunction = (accountId: number, projectName: string, currentBuildId: number) => Promise<void> | void;
3
3
  export declare function createWatcher(accountId: number, projectConfig: ProjectConfig, projectDir: string, handleBuildStatusFn: ProjectWatchHandlerFunction, handleUserInputFn: ProjectWatchHandlerFunction): Promise<void>;
4
4
  export {};
@@ -1,12 +1,19 @@
1
1
  import { ProjectTemplate } from '../../types/Projects';
2
- type CreateProjectPromptResponse = {
2
+ type CreateProjectPromptResponseWithTemplate = {
3
3
  name: string;
4
4
  dest: string;
5
- projectTemplate?: ProjectTemplate;
5
+ projectTemplate: ProjectTemplate;
6
6
  };
7
- export declare function createProjectPrompt(promptOptions: {
7
+ type CreateProjectPromptResponseWithoutTemplate = {
8
+ name: string;
9
+ dest: string;
10
+ projectTemplate?: undefined;
11
+ };
12
+ type PromptOptionsArg = {
8
13
  name?: string;
9
14
  dest?: string;
10
15
  template?: string;
11
- }, projectTemplates?: ProjectTemplate[]): Promise<CreateProjectPromptResponse>;
16
+ };
17
+ export declare function createProjectPrompt(promptOptions: PromptOptionsArg, projectTemplates: ProjectTemplate[]): Promise<CreateProjectPromptResponseWithTemplate>;
18
+ export declare function createProjectPrompt(promptOptions: PromptOptionsArg, projectTemplates?: undefined): Promise<CreateProjectPromptResponseWithoutTemplate>;
12
19
  export {};
@@ -86,5 +86,11 @@ async function createProjectPrompt(promptOptions, projectTemplates) {
86
86
  if (providedTemplateIsValid) {
87
87
  result.projectTemplate = findTemplateByNameOrLabel(projectTemplates, promptOptions.template);
88
88
  }
89
+ if (projectTemplates && projectTemplates.length > 0) {
90
+ if (!result.projectTemplate) {
91
+ throw new Error((0, lang_1.i18n)(`${i18nKey}.errors.projectTemplateRequired`));
92
+ }
93
+ return result;
94
+ }
89
95
  return result;
90
96
  }
package/lib/ui/index.d.ts CHANGED
@@ -11,8 +11,9 @@ export declare function uiCommandReference(command: string, withQuotes?: boolean
11
11
  export declare function uiFeatureHighlight(features: string[], title?: string): void;
12
12
  export declare function uiBetaTag(message: string, log?: true): undefined;
13
13
  export declare function uiBetaTag(message: string, log: false): string;
14
- export declare function uiDeprecatedTag(message: string, log?: boolean): string | undefined;
14
+ export declare function uiDeprecatedTag(message: string, log?: true): undefined;
15
+ export declare function uiDeprecatedTag(message: string, log: false): string;
15
16
  export declare function uiCommandDisabledBanner(command: string, url?: string, message?: string): void;
16
- export declare function uiDeprecatedDescription(message: string, command: string, url?: string): string | undefined;
17
+ export declare function uiDeprecatedDescription(message: string, command: string, url?: string): undefined;
17
18
  export declare function uiDeprecatedMessage(command: string, url?: string, message?: string): void;
18
19
  export declare function indent(level: number): string;
package/lib/ui/index.js CHANGED
@@ -112,6 +112,7 @@ function uiDeprecatedTag(message, log = true) {
112
112
  const result = `${terminalUISupport.color ? chalk_1.default.yellow(tag) : tag} ${message}`;
113
113
  if (log) {
114
114
  logger_1.logger.log(result);
115
+ return;
115
116
  }
116
117
  return result;
117
118
  }