@hubspot/cli 7.7.16-experimental.0 → 7.7.16-experimental.10

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 (106) hide show
  1. package/bin/cli.js +4 -0
  2. package/bin/hs +1 -1
  3. package/commands/account/auth.js +3 -3
  4. package/commands/app/install.d.ts +8 -0
  5. package/commands/app/install.js +127 -0
  6. package/commands/app.js +6 -1
  7. package/commands/auth.js +23 -25
  8. package/commands/getStarted.d.ts +9 -0
  9. package/commands/getStarted.js +274 -0
  10. package/commands/init.js +35 -32
  11. package/commands/mcp/setup.d.ts +2 -2
  12. package/commands/mcp/setup.js +2 -0
  13. package/commands/mcp/start.d.ts +2 -2
  14. package/commands/mcp/start.js +3 -1
  15. package/commands/project/cloneApp.js +4 -4
  16. package/commands/project/create.js +9 -9
  17. package/commands/project/deploy.d.ts +1 -0
  18. package/commands/project/deploy.js +29 -3
  19. package/commands/project/dev/deprecatedFlow.js +4 -4
  20. package/commands/project/dev/index.js +5 -5
  21. package/commands/project/dev/unifiedFlow.js +8 -0
  22. package/commands/project/upload.d.ts +2 -2
  23. package/commands/project/upload.js +18 -23
  24. package/commands/project/validate.d.ts +6 -0
  25. package/commands/project/validate.js +82 -0
  26. package/commands/project.js +2 -0
  27. package/commands/sandbox/delete.js +5 -5
  28. package/commands/testAccount/create.d.ts +6 -0
  29. package/commands/testAccount/create.js +160 -0
  30. package/commands/testAccount/createConfig.d.ts +10 -0
  31. package/commands/testAccount/createConfig.js +98 -0
  32. package/commands/testAccount/delete.d.ts +6 -0
  33. package/commands/testAccount/delete.js +48 -0
  34. package/commands/testAccount.d.ts +3 -0
  35. package/commands/testAccount.js +28 -0
  36. package/lang/en.d.ts +201 -35
  37. package/lang/en.js +201 -38
  38. package/lang/en.lyaml +9 -14
  39. package/lib/accountTypes.d.ts +1 -0
  40. package/lib/accountTypes.js +20 -9
  41. package/lib/app/migrate.js +15 -3
  42. package/lib/app/migrate_legacy.js +2 -3
  43. package/lib/app/urls.d.ts +1 -1
  44. package/lib/commonOpts.d.ts +2 -0
  45. package/lib/commonOpts.js +21 -9
  46. package/lib/constants.d.ts +5 -0
  47. package/lib/constants.js +6 -1
  48. package/lib/doctor/Doctor.js +1 -1
  49. package/lib/errorHandlers/index.js +7 -0
  50. package/lib/mcp/setup.d.ts +9 -0
  51. package/lib/mcp/setup.js +23 -21
  52. package/lib/middleware/__test__/configMiddleware.test.js +2 -2
  53. package/lib/middleware/configMiddleware.js +10 -2
  54. package/lib/parsing.d.ts +1 -0
  55. package/lib/parsing.js +11 -0
  56. package/lib/polling.d.ts +1 -1
  57. package/lib/polling.js +11 -1
  58. package/lib/projectProfiles.d.ts +1 -0
  59. package/lib/projectProfiles.js +18 -0
  60. package/lib/projects/add/v3AddComponent.js +4 -0
  61. package/lib/projects/buildAndDeploy.js +1 -1
  62. package/lib/projects/create/index.d.ts +3 -2
  63. package/lib/projects/create/index.js +11 -5
  64. package/lib/projects/create/v3.d.ts +3 -3
  65. package/lib/projects/create/v3.js +2 -2
  66. package/lib/projects/localDev/AppDevModeInterface.d.ts +3 -0
  67. package/lib/projects/localDev/AppDevModeInterface.js +46 -17
  68. package/lib/projects/localDev/LocalDevManager.js +1 -1
  69. package/lib/projects/localDev/LocalDevProcess.d.ts +3 -2
  70. package/lib/projects/localDev/LocalDevProcess.js +16 -12
  71. package/lib/projects/localDev/LocalDevState.d.ts +10 -5
  72. package/lib/projects/localDev/LocalDevState.js +18 -20
  73. package/lib/projects/localDev/LocalDevWatcher.js +1 -1
  74. package/lib/projects/structure.d.ts +2 -2
  75. package/lib/projects/upload.d.ts +4 -0
  76. package/lib/projects/upload.js +57 -22
  77. package/lib/projects/urls.d.ts +2 -0
  78. package/lib/projects/urls.js +10 -0
  79. package/lib/prompts/createDeveloperTestAccountConfigPrompt.d.ts +17 -0
  80. package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +96 -0
  81. package/lib/prompts/installAppPrompt.d.ts +2 -1
  82. package/lib/prompts/installAppPrompt.js +12 -2
  83. package/lib/prompts/personalAccessKeyPrompt.js +2 -2
  84. package/lib/prompts/projectNameAndDestPrompt.d.ts +3 -0
  85. package/lib/prompts/projectNameAndDestPrompt.js +60 -0
  86. package/lib/prompts/promptUtils.d.ts +1 -0
  87. package/lib/prompts/promptUtils.js +2 -0
  88. package/lib/prompts/selectProjectTemplatePrompt.d.ts +26 -0
  89. package/lib/prompts/{createProjectPrompt.js → selectProjectTemplatePrompt.js} +6 -55
  90. package/lib/ui/logger.d.ts +1 -0
  91. package/lib/ui/logger.js +1 -0
  92. package/lib/validation.d.ts +1 -1
  93. package/lib/validation.js +4 -4
  94. package/lib/yargsUtils.d.ts +1 -0
  95. package/lib/yargsUtils.js +3 -0
  96. package/mcp-server/tools/index.js +2 -0
  97. package/mcp-server/tools/project/CreateProjectTool.d.ts +3 -3
  98. package/mcp-server/tools/project/CreateProjectTool.js +5 -1
  99. package/mcp-server/tools/project/DeployProject.js +1 -1
  100. package/mcp-server/tools/project/UploadProjectTools.js +1 -1
  101. package/mcp-server/tools/project/ValidateProjectTool.d.ts +17 -0
  102. package/mcp-server/tools/project/ValidateProjectTool.js +35 -0
  103. package/package.json +10 -9
  104. package/types/LocalDev.d.ts +2 -0
  105. package/types/Yargs.d.ts +5 -1
  106. package/lib/prompts/createProjectPrompt.d.ts +0 -28
package/commands/init.js CHANGED
@@ -13,13 +13,11 @@ const personalAccessKey_1 = require("@hubspot/local-dev-lib/personalAccessKey");
13
13
  const path_2 = require("@hubspot/local-dev-lib/path");
14
14
  const text_1 = require("@hubspot/local-dev-lib/text");
15
15
  const environments_1 = require("@hubspot/local-dev-lib/constants/environments");
16
- const logger_1 = require("@hubspot/local-dev-lib/logger");
17
16
  const getAccountIdentifier_1 = require("@hubspot/local-dev-lib/config/getAccountIdentifier");
18
17
  const commonOpts_1 = require("../lib/commonOpts");
19
18
  const yargsUtils_1 = require("../lib/yargsUtils");
20
19
  const process_1 = require("../lib/process");
21
20
  const index_1 = require("../lib/errorHandlers/index");
22
- const lang_1 = require("../lib/lang");
23
21
  const usageTracking_1 = require("../lib/usageTracking");
24
22
  const promptUtils_1 = require("../lib/prompts/promptUtils");
25
23
  const personalAccessKeyPrompt_1 = require("../lib/prompts/personalAccessKeyPrompt");
@@ -27,6 +25,9 @@ const accountNamePrompt_1 = require("../lib/prompts/accountNamePrompt");
27
25
  const oauth_1 = require("../lib/oauth");
28
26
  const exitCodes_1 = require("../lib/enums/exitCodes");
29
27
  const ui_1 = require("../lib/ui");
28
+ const logger_1 = require("../lib/ui/logger");
29
+ const en_1 = require("../lang/en");
30
+ const parsing_1 = require("../lib/parsing");
30
31
  const TRACKING_STATUS = {
31
32
  STARTED: 'started',
32
33
  ERROR: 'error',
@@ -61,9 +62,19 @@ const AUTH_TYPE_NAMES = {
61
62
  [auth_1.OAUTH_AUTH_METHOD.value]: auth_1.OAUTH_AUTH_METHOD.name,
62
63
  };
63
64
  const command = 'init';
64
- const describe = (0, lang_1.i18n)(`commands.init.describe`);
65
+ const describe = en_1.commands.init.describe;
65
66
  async function handler(args) {
66
- const { authType: authTypeFlagValue, c: configFlagValue, providedAccountId, disableTracking, useHiddenConfig, } = args;
67
+ const { authType: authTypeFlagValue, c: configFlagValue, disableTracking, useHiddenConfig, userProvidedAccount, } = args;
68
+ let parsedUserProvidedAccountId;
69
+ try {
70
+ if (userProvidedAccount) {
71
+ parsedUserProvidedAccountId = (0, parsing_1.parseStringToNumber)(userProvidedAccount);
72
+ }
73
+ }
74
+ catch (err) {
75
+ logger_1.uiLogger.error(en_1.commands.init.errors.invalidAccountIdProvided);
76
+ process.exit(exitCodes_1.EXIT_CODES.ERROR);
77
+ }
67
78
  const authType = (authTypeFlagValue && authTypeFlagValue.toLowerCase()) ||
68
79
  auth_1.PERSONAL_ACCESS_KEY_AUTH_METHOD.value;
69
80
  const configPath = (configFlagValue && path_1.default.join((0, path_2.getCwd)(), configFlagValue)) ||
@@ -76,28 +87,24 @@ async function handler(args) {
76
87
  }
77
88
  const env = args.qa ? environments_1.ENVIRONMENTS.QA : environments_1.ENVIRONMENTS.PROD;
78
89
  if ((0, config_1.configFileExists)(true)) {
79
- logger_1.logger.error((0, lang_1.i18n)(`commands.init.errors.globalConfigFileExists`, {
80
- accountAuthCommand: (0, ui_1.uiCommandReference)('hs account auth'),
81
- }));
90
+ logger_1.uiLogger.error(en_1.commands.init.errors.globalConfigFileExists);
82
91
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
83
92
  }
84
93
  if (fs_extra_1.default.existsSync(configPath)) {
85
- logger_1.logger.error((0, lang_1.i18n)(`commands.init.errors.configFileExists`, {
86
- configPath: configPath,
87
- }));
88
- logger_1.logger.info((0, lang_1.i18n)(`commands.init.logs.updateConfig`));
94
+ logger_1.uiLogger.error(en_1.commands.init.errors.configFileExists(configPath));
95
+ logger_1.uiLogger.info(en_1.commands.init.logs.updateConfig);
89
96
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
90
97
  }
91
98
  if (!disableTracking) {
92
- await (0, usageTracking_1.trackAuthAction)('init', authType, TRACKING_STATUS.STARTED, providedAccountId);
99
+ await (0, usageTracking_1.trackAuthAction)('init', authType, TRACKING_STATUS.STARTED, parsedUserProvidedAccountId);
93
100
  }
94
101
  const doesOtherConfigFileExist = (0, config_1.configFileExists)(!useHiddenConfig);
95
102
  if (doesOtherConfigFileExist) {
96
103
  const path = (0, config_1.getConfigPath)('', !useHiddenConfig);
97
- logger_1.logger.error((0, lang_1.i18n)(`commands.init.errors.bothConfigFilesNotAllowed`, { path: path }));
104
+ logger_1.uiLogger.error(en_1.commands.init.errors.bothConfigFilesNotAllowed(path));
98
105
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
99
106
  }
100
- (0, usageTracking_1.trackAuthAction)('init', authType, TRACKING_STATUS.STARTED, providedAccountId);
107
+ (0, usageTracking_1.trackAuthAction)('init', authType, TRACKING_STATUS.STARTED, parsedUserProvidedAccountId);
101
108
  (0, config_1.createEmptyConfigFile)({ path: configPath }, useHiddenConfig);
102
109
  //Needed to load deprecated config
103
110
  (0, config_1.loadConfig)(configPath, args);
@@ -106,7 +113,7 @@ async function handler(args) {
106
113
  let accountId;
107
114
  let name;
108
115
  if (authType === auth_1.PERSONAL_ACCESS_KEY_AUTH_METHOD.value) {
109
- const personalAccessKeyResult = await personalAccessKeyConfigCreationFlow(env, providedAccountId);
116
+ const personalAccessKeyResult = await personalAccessKeyConfigCreationFlow(env, parsedUserProvidedAccountId);
110
117
  if (personalAccessKeyResult) {
111
118
  accountId = (0, getAccountIdentifier_1.getAccountIdentifier)(personalAccessKeyResult);
112
119
  name = personalAccessKeyResult.name;
@@ -124,15 +131,15 @@ async function handler(args) {
124
131
  catch (e) {
125
132
  (0, index_1.debugError)(e);
126
133
  }
127
- logger_1.logger.log('');
128
- logger_1.logger.success((0, lang_1.i18n)(`commands.init.success.configFileCreated`, {
129
- configPath: configPath,
130
- }));
131
- logger_1.logger.success((0, lang_1.i18n)(`commands.init.success.configFileUpdated`, {
132
- authType: AUTH_TYPE_NAMES[authType],
133
- account: name || accountId,
134
- }));
135
- (0, ui_1.uiFeatureHighlight)(['helpCommand', 'authCommand', 'accountsListCommand']);
134
+ logger_1.uiLogger.log('');
135
+ logger_1.uiLogger.success(en_1.commands.init.success.configFileCreated(configPath));
136
+ logger_1.uiLogger.success(en_1.commands.init.success.configFileUpdated(AUTH_TYPE_NAMES[authType], name || accountId));
137
+ (0, ui_1.uiFeatureHighlight)([
138
+ 'getStartedCommand',
139
+ 'helpCommand',
140
+ 'authCommand',
141
+ 'accountsListCommand',
142
+ ]);
136
143
  if (!disableTracking) {
137
144
  await (0, usageTracking_1.trackAuthAction)('init', authType, TRACKING_STATUS.COMPLETE, accountId);
138
145
  }
@@ -141,7 +148,7 @@ async function handler(args) {
141
148
  catch (err) {
142
149
  (0, index_1.logError)(err);
143
150
  if (!disableTracking) {
144
- await (0, usageTracking_1.trackAuthAction)('init', authType, TRACKING_STATUS.ERROR, providedAccountId);
151
+ await (0, usageTracking_1.trackAuthAction)('init', authType, TRACKING_STATUS.ERROR, parsedUserProvidedAccountId);
145
152
  }
146
153
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
147
154
  }
@@ -149,7 +156,7 @@ async function handler(args) {
149
156
  function initBuilder(yargs) {
150
157
  yargs.options({
151
158
  'auth-type': {
152
- describe: (0, lang_1.i18n)(`commands.init.options.authType.describe`),
159
+ describe: en_1.commands.init.options.authType.describe,
153
160
  type: 'string',
154
161
  choices: [
155
162
  `${auth_1.PERSONAL_ACCESS_KEY_AUTH_METHOD.value}`,
@@ -158,7 +165,7 @@ function initBuilder(yargs) {
158
165
  default: auth_1.PERSONAL_ACCESS_KEY_AUTH_METHOD.value,
159
166
  },
160
167
  account: {
161
- describe: (0, lang_1.i18n)(`commands.init.options.account.describe`),
168
+ describe: en_1.commands.init.options.account.describe,
162
169
  type: 'string',
163
170
  alias: 'a',
164
171
  },
@@ -171,11 +178,7 @@ function initBuilder(yargs) {
171
178
  yargs.conflicts('use-hidden-config', 'config');
172
179
  return yargs;
173
180
  }
174
- const builder = (0, yargsUtils_1.makeYargsBuilder)(initBuilder, command, (0, lang_1.i18n)(`commands.init.verboseDescribe`, {
175
- command: (0, ui_1.uiCommandReference)('hs auth'),
176
- configName: config_2.DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME,
177
- authMethod: auth_1.PERSONAL_ACCESS_KEY_AUTH_METHOD.value,
178
- }), {
181
+ const builder = (0, yargsUtils_1.makeYargsBuilder)(initBuilder, command, en_1.commands.init.verboseDescribe(config_2.DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME, (0, ui_1.uiCommandReference)('hs auth'), auth_1.PERSONAL_ACCESS_KEY_AUTH_METHOD.value), {
179
182
  useGlobalOptions: true,
180
183
  useConfigOptions: true,
181
184
  useTestingOptions: true,
@@ -1,5 +1,5 @@
1
- import { YargsCommandModule } from '../../types/Yargs';
2
- interface MCPSetupArgs {
1
+ import { CommonArgs, YargsCommandModule } from '../../types/Yargs';
2
+ interface MCPSetupArgs extends CommonArgs {
3
3
  client?: string[];
4
4
  addDocsSearch?: boolean;
5
5
  }
@@ -5,6 +5,7 @@ const yargsUtils_1 = require("../../lib/yargsUtils");
5
5
  const en_1 = require("../../lang/en");
6
6
  const logger_1 = require("../../lib/ui/logger");
7
7
  const setup_1 = require("../../lib/mcp/setup");
8
+ const usageTracking_1 = require("../../lib/usageTracking");
8
9
  const command = ['setup', 'update'];
9
10
  const describe = undefined; // Leave hidden for now
10
11
  async function handler(args) {
@@ -15,6 +16,7 @@ async function handler(args) {
15
16
  logger_1.uiLogger.error(en_1.commands.mcp.setup.errors.needsNode20);
16
17
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
17
18
  }
19
+ (0, usageTracking_1.trackCommandUsage)('mcp-setup', {}, args.derivedAccountId);
18
20
  try {
19
21
  const derivedTargets = await (0, setup_1.addMcpServerToConfig)(args.client);
20
22
  if (args.addDocsSearch) {
@@ -1,3 +1,3 @@
1
- import { YargsCommandModule } from '../../types/Yargs';
2
- declare const mcpStartCommand: YargsCommandModule<unknown, unknown>;
1
+ import { CommonArgs, YargsCommandModule } from '../../types/Yargs';
2
+ declare const mcpStartCommand: YargsCommandModule<unknown, CommonArgs>;
3
3
  export default mcpStartCommand;
@@ -12,9 +12,10 @@ const logger_1 = require("../../lib/ui/logger");
12
12
  const errorHandlers_1 = require("../../lib/errorHandlers");
13
13
  const en_1 = require("../../lang/en");
14
14
  const process_1 = require("../../lib/process");
15
+ const usageTracking_1 = require("../../lib/usageTracking");
15
16
  const command = 'start';
16
17
  const describe = undefined; // Leave hidden for now
17
- async function handler() {
18
+ async function handler(args) {
18
19
  try {
19
20
  await import('@modelcontextprotocol/sdk/server/mcp.js');
20
21
  }
@@ -22,6 +23,7 @@ async function handler() {
22
23
  logger_1.uiLogger.error(en_1.commands.mcp.start.errors.needsNode20);
23
24
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
24
25
  }
26
+ (0, usageTracking_1.trackCommandUsage)('mcp-start', {}, args.derivedAccountId);
25
27
  await startMcpServer();
26
28
  }
27
29
  async function startMcpServer() {
@@ -8,7 +8,7 @@ const fs_1 = __importDefault(require("fs"));
8
8
  const usageTracking_1 = require("../../lib/usageTracking");
9
9
  const lang_1 = require("../../lib/lang");
10
10
  const selectPublicAppForMigrationPrompt_1 = require("../../lib/prompts/selectPublicAppForMigrationPrompt");
11
- const createProjectPrompt_1 = require("../../lib/prompts/createProjectPrompt");
11
+ const projectNameAndDestPrompt_1 = require("../../lib/prompts/projectNameAndDestPrompt");
12
12
  const polling_1 = require("../../lib/polling");
13
13
  const errorHandlers_1 = require("../../lib/errorHandlers");
14
14
  const exitCodes_1 = require("../../lib/enums/exitCodes");
@@ -53,9 +53,9 @@ async function handler(args) {
53
53
  });
54
54
  appId = appIdResponse.appId;
55
55
  }
56
- const createProjectPromptResponse = await (0, createProjectPrompt_1.createProjectPrompt)(args);
57
- projectName = createProjectPromptResponse.name;
58
- projectDest = createProjectPromptResponse.dest;
56
+ const projectNameAndDestPromptResponse = await (0, projectNameAndDestPrompt_1.projectNameAndDestPrompt)(args);
57
+ projectName = projectNameAndDestPromptResponse.name;
58
+ projectDest = projectNameAndDestPromptResponse.dest;
59
59
  }
60
60
  catch (error) {
61
61
  (0, errorHandlers_1.logError)(error, new errorHandlers_1.ApiErrorContext({ accountId: derivedAccountId }));
@@ -39,15 +39,15 @@ async function handler(args) {
39
39
  (0, errorHandlers_1.logError)(error);
40
40
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
41
41
  }
42
- const { authType, distribution, repoConfig, projectContents, createProjectPromptResponse, } = handleResult;
42
+ const { authType, distribution, repoConfig, projectContents, selectProjectTemplatePromptResponse, projectNameAndDestPromptResponse, } = handleResult;
43
43
  (0, usageTracking_1.trackCommandUsage)('project-create', {
44
- type: createProjectPromptResponse.projectTemplate?.name ||
45
- (createProjectPromptResponse.componentTemplates || [])
44
+ type: selectProjectTemplatePromptResponse.projectTemplate?.name ||
45
+ (selectProjectTemplatePromptResponse.componentTemplates || [])
46
46
  // @ts-expect-error
47
47
  .map((item) => item.label)
48
48
  .join(','),
49
49
  }, derivedAccountId);
50
- const projectDest = path_1.default.resolve((0, path_2.getCwd)(), createProjectPromptResponse.dest);
50
+ const projectDest = path_1.default.resolve((0, path_2.getCwd)(), projectNameAndDestPromptResponse.dest);
51
51
  const { projectConfig: existingProjectConfig, projectDir: existingProjectDir, } = await (0, config_1.getProjectConfig)(projectDest);
52
52
  // Exit if the target destination is within an existing project
53
53
  if (existingProjectConfig &&
@@ -57,7 +57,7 @@ async function handler(args) {
57
57
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
58
58
  }
59
59
  const components = (0, v3_2.generateComponentPaths)({
60
- createProjectPromptResponse,
60
+ selectProjectTemplatePromptResponse,
61
61
  platformVersion,
62
62
  repoConfig,
63
63
  projectContents,
@@ -66,7 +66,7 @@ async function handler(args) {
66
66
  });
67
67
  try {
68
68
  await (0, github_1.cloneGithubRepo)(repo, projectDest, {
69
- sourceDir: createProjectPromptResponse.projectTemplate?.path || components,
69
+ sourceDir: selectProjectTemplatePromptResponse.projectTemplate?.path || components,
70
70
  hideLogs: true,
71
71
  branch: 'main',
72
72
  });
@@ -80,15 +80,15 @@ async function handler(args) {
80
80
  const parsedConfigFile = JSON.parse(fs_extra_1.default.readFileSync(projectConfigPath).toString());
81
81
  (0, config_1.writeProjectConfig)(projectConfigPath, {
82
82
  ...parsedConfigFile,
83
- name: createProjectPromptResponse.name,
83
+ name: projectNameAndDestPromptResponse.name,
84
84
  });
85
85
  // If the template is 'no-template', we need to manually create a src directory
86
- if (createProjectPromptResponse.projectTemplate?.name ===
86
+ if (selectProjectTemplatePromptResponse.projectTemplate?.name ===
87
87
  legacy_1.EMPTY_PROJECT_TEMPLATE_NAME ||
88
88
  projectContents === v3_1.EMPTY_PROJECT) {
89
89
  fs_extra_1.default.ensureDirSync(path_1.default.join(projectDest, 'src'));
90
90
  }
91
- logger_1.uiLogger.success(en_1.commands.project.create.logs.success(createProjectPromptResponse.name, projectDest));
91
+ logger_1.uiLogger.success(en_1.commands.project.create.logs.success(projectNameAndDestPromptResponse.name, projectDest));
92
92
  logger_1.uiLogger.log(en_1.commands.project.create.logs.welcomeMessage);
93
93
  (0, ui_1.uiFeatureHighlight)([
94
94
  'projectCommandTip',
@@ -4,6 +4,7 @@ export type ProjectDeployArgs = CommonArgs & ConfigArgs & AccountArgs & Environm
4
4
  build?: number;
5
5
  buildId?: number;
6
6
  profile?: string;
7
+ force: boolean;
7
8
  };
8
9
  declare const projectDeployCommand: YargsCommandModule<unknown, ProjectDeployArgs>;
9
10
  export default projectDeployCommand;
@@ -22,6 +22,7 @@ const exitCodes_1 = require("../../lib/enums/exitCodes");
22
22
  const ui_2 = require("../../lib/ui");
23
23
  const yargsUtils_1 = require("../../lib/yargsUtils");
24
24
  const projectProfiles_1 = require("../../lib/projectProfiles");
25
+ const constants_1 = require("../../lib/constants");
25
26
  const command = 'deploy';
26
27
  const describe = (0, ui_1.uiBetaTag)((0, lang_1.i18n)(`commands.project.subcommands.deploy.describe`), false);
27
28
  function validateBuildId(buildId, deployedBuildId, latestBuildId, projectName, accountId) {
@@ -40,8 +41,22 @@ function validateBuildId(buildId, deployedBuildId, latestBuildId, projectName, a
40
41
  }
41
42
  return true;
42
43
  }
44
+ function logDeployErrors(errorData) {
45
+ logger_1.logger.error(errorData.message);
46
+ errorData.errors.forEach(err => {
47
+ if (err.subCategory === constants_1.PROJECT_ERROR_TYPES.DEPLOY_CONTAINS_REMOVALS) {
48
+ logger_1.logger.log((0, lang_1.i18n)(`commands.project.subcommands.deploy.errors.deployContainsRemovals`, {
49
+ componentName: err.context.COMPONENT_NAME,
50
+ forceFlag: (0, ui_2.uiCommandReference)('--force'),
51
+ }));
52
+ }
53
+ else {
54
+ logger_1.logger.log(err.message);
55
+ }
56
+ });
57
+ }
43
58
  async function handler(args) {
44
- const { derivedAccountId, project: projectOption, buildId: buildIdOption, } = args;
59
+ const { derivedAccountId, project: projectOption, buildId: buildIdOption, force: forceOption, } = args;
45
60
  const accountConfig = (0, config_1.getAccountConfig)(derivedAccountId);
46
61
  const accountType = accountConfig && accountConfig.accountType;
47
62
  let targetAccountId;
@@ -103,7 +118,7 @@ async function handler(args) {
103
118
  logger_1.logger.error((0, lang_1.i18n)(`commands.project.subcommands.deploy.errors.noBuildId`));
104
119
  return process.exit(exitCodes_1.EXIT_CODES.ERROR);
105
120
  }
106
- const { data: deployResp } = await (0, projects_1.deployProject)(targetAccountId, projectName, buildIdToDeploy, (0, buildAndDeploy_1.useV3Api)(projectConfig?.platformVersion));
121
+ const { data: deployResp } = await (0, projects_1.deployProject)(targetAccountId, projectName, buildIdToDeploy, (0, buildAndDeploy_1.useV3Api)(projectConfig?.platformVersion), forceOption);
107
122
  if (!deployResp) {
108
123
  logger_1.logger.error((0, lang_1.i18n)(`commands.project.subcommands.deploy.errors.deploy`));
109
124
  return process.exit(exitCodes_1.EXIT_CODES.ERROR);
@@ -119,7 +134,12 @@ async function handler(args) {
119
134
  }));
120
135
  }
121
136
  else if ((0, index_1.isHubSpotHttpError)(e) && e.status === 400) {
122
- logger_1.logger.error(e.message);
137
+ if (e.data?.message && e.data?.errors) {
138
+ logDeployErrors(e.data);
139
+ }
140
+ else {
141
+ logger_1.logger.error(e.message);
142
+ }
123
143
  }
124
144
  else {
125
145
  (0, index_2.logError)(e, new index_2.ApiErrorContext({
@@ -147,6 +167,12 @@ function projectDeployBuilder(yargs) {
147
167
  type: 'string',
148
168
  hidden: true,
149
169
  },
170
+ force: {
171
+ alias: ['f'],
172
+ describe: (0, lang_1.i18n)(`commands.project.subcommands.deploy.options.force.describe`),
173
+ default: false,
174
+ type: 'boolean',
175
+ },
150
176
  });
151
177
  yargs.conflicts('profile', 'project');
152
178
  yargs.conflicts('profile', 'account');
@@ -19,7 +19,7 @@ const process_1 = require("../../../lib/process");
19
19
  const accountTypes_1 = require("../../../lib/accountTypes");
20
20
  const ensureProjectExists_1 = require("../../../lib/projects/ensureProjectExists");
21
21
  async function deprecatedProjectDevFlow({ args, accountId, projectConfig, projectDir, }) {
22
- const { providedAccountId, derivedAccountId } = args;
22
+ const { userProvidedAccount, derivedAccountId } = args;
23
23
  const env = (0, environment_1.getValidEnv)((0, config_1.getEnv)(derivedAccountId));
24
24
  const components = await (0, structure_1.findProjectComponents)(projectDir);
25
25
  const runnableComponents = components.filter(component => component.runnable);
@@ -65,11 +65,11 @@ async function deprecatedProjectDevFlow({ args, accountId, projectConfig, projec
65
65
  }
66
66
  // targetProjectAccountId and targetTestingAccountId are set to null if --account flag is not provided.
67
67
  // By setting them to null, we can later check if they need to be assigned based on the default account configuration and the type of app.
68
- let targetProjectAccountId = providedAccountId ? derivedAccountId : null;
68
+ let targetProjectAccountId = userProvidedAccount ? derivedAccountId : null;
69
69
  // The account that we are locally testing against
70
- let targetTestingAccountId = providedAccountId ? derivedAccountId : null;
70
+ let targetTestingAccountId = userProvidedAccount ? derivedAccountId : null;
71
71
  // Check that the default account or flag option is valid for the type of app in this project
72
- if (providedAccountId) {
72
+ if (userProvidedAccount) {
73
73
  (0, helpers_1.checkIfAccountFlagIsSupported)(accountConfig, hasPublicApps);
74
74
  if (hasPublicApps) {
75
75
  targetProjectAccountId = accountConfig.parentAccountId || null;
@@ -15,19 +15,19 @@ const en_1 = require("../../../lang/en");
15
15
  const logger_1 = require("../../../lib/ui/logger");
16
16
  const command = 'dev';
17
17
  const describe = (0, ui_1.uiBetaTag)(en_1.commands.project.dev.describe, false);
18
- function validateAccountFlags(testingAccount, projectAccount, providedAccountId, useV3) {
18
+ function validateAccountFlags(testingAccount, projectAccount, userProvidedAccount, useV3) {
19
19
  // Legacy projects do not support targetTestingAccount and targetProjectAccount
20
20
  if (testingAccount && projectAccount && !useV3) {
21
21
  logger_1.uiLogger.error(en_1.commands.project.dev.errors.unsupportedAccountFlagLegacy);
22
22
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
23
23
  }
24
- if (providedAccountId && useV3) {
24
+ if (userProvidedAccount && useV3) {
25
25
  logger_1.uiLogger.error(en_1.commands.project.dev.errors.unsupportedAccountFlagV3);
26
26
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
27
27
  }
28
28
  }
29
29
  async function handler(args) {
30
- const { derivedAccountId, providedAccountId, testingAccount, projectAccount, } = args;
30
+ const { derivedAccountId, userProvidedAccount, testingAccount, projectAccount, } = args;
31
31
  const { projectConfig, projectDir } = await (0, config_2.getProjectConfig)();
32
32
  (0, config_2.validateProjectConfig)(projectConfig, projectDir);
33
33
  const useV3 = (0, buildAndDeploy_1.useV3Api)(projectConfig.platformVersion);
@@ -35,9 +35,9 @@ async function handler(args) {
35
35
  logger_1.uiLogger.error(en_1.commands.project.dev.errors.noProjectConfig);
36
36
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
37
37
  }
38
- validateAccountFlags(testingAccount, projectAccount, providedAccountId, useV3);
38
+ validateAccountFlags(testingAccount, projectAccount, userProvidedAccount, useV3);
39
39
  let targetProjectAccountId = (projectAccount && (0, config_1.getAccountId)(projectAccount)) ||
40
- (providedAccountId && derivedAccountId);
40
+ (userProvidedAccount && derivedAccountId);
41
41
  let profile;
42
42
  if (!targetProjectAccountId && (0, buildAndDeploy_1.useV3Api)(projectConfig.platformVersion)) {
43
43
  if (args.profile) {
@@ -58,6 +58,7 @@ async function unifiedProjectDevFlow({ args, targetProjectAccountId, providedTar
58
58
  }
59
59
  const accounts = (0, config_2.getConfigAccounts)();
60
60
  const accountIsCombined = await (0, accountTypes_1.isUnifiedAccount)(targetProjectAccountConfig);
61
+ const targetProjectAccountIsTestAccountOrSandbox = (0, accountTypes_1.isTestAccountOrSandbox)(targetProjectAccountConfig);
61
62
  if (!accountIsCombined && !profileConfig) {
62
63
  logger_1.uiLogger.error(en_1.commands.project.dev.errors.accountNotCombined);
63
64
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
@@ -67,6 +68,12 @@ async function unifiedProjectDevFlow({ args, targetProjectAccountId, providedTar
67
68
  // Bypass the prompt for the testing account if the user has a profile configured
68
69
  targetTestingAccountId = profileConfig.accountId;
69
70
  }
71
+ else if (
72
+ // Bypass the prompt for the testing account if default account is already a test account
73
+ !targetTestingAccountId &&
74
+ targetProjectAccountIsTestAccountOrSandbox) {
75
+ targetTestingAccountId = targetProjectAccountId;
76
+ }
70
77
  else if (!targetTestingAccountId) {
71
78
  logger_1.uiLogger.log('');
72
79
  (0, ui_1.uiLine)();
@@ -121,6 +128,7 @@ async function unifiedProjectDevFlow({ args, targetProjectAccountId, providedTar
121
128
  debug: args.debug,
122
129
  deployedBuild,
123
130
  isGithubLinked,
131
+ profile: args.profile,
124
132
  targetProjectAccountId,
125
133
  targetTestingAccountId: targetTestingAccountId,
126
134
  projectConfig,
@@ -1,5 +1,5 @@
1
- import { CommonArgs, YargsCommandModule } from '../../types/Yargs';
2
- type ProjectUploadArgs = CommonArgs & {
1
+ import { CommonArgs, JSONOutputArgs, YargsCommandModule } from '../../types/Yargs';
2
+ type ProjectUploadArgs = CommonArgs & JSONOutputArgs & {
3
3
  forceCreate: boolean;
4
4
  message: string;
5
5
  m: string;
@@ -13,40 +13,26 @@ const usageTracking_1 = require("../../lib/usageTracking");
13
13
  const config_2 = require("../../lib/projects/config");
14
14
  const ui_2 = require("../../lib/projects/ui");
15
15
  const upload_1 = require("../../lib/projects/upload");
16
+ const projectProfiles_1 = require("../../lib/projectProfiles");
16
17
  const buildAndDeploy_2 = require("../../lib/projects/buildAndDeploy");
17
18
  const lang_1 = require("../../lib/lang");
18
19
  const constants_1 = require("../../lib/constants");
19
20
  const index_2 = require("../../lib/errorHandlers/index");
20
21
  const exitCodes_1 = require("../../lib/enums/exitCodes");
21
22
  const yargsUtils_1 = require("../../lib/yargsUtils");
22
- const projectProfiles_1 = require("../../lib/projectProfiles");
23
+ const logger_2 = require("../../lib/ui/logger");
23
24
  const command = 'upload';
24
25
  const describe = (0, ui_1.uiBetaTag)((0, lang_1.i18n)(`commands.project.subcommands.upload.describe`), false);
25
26
  async function handler(args) {
26
- const { forceCreate, message, derivedAccountId, providedAccountId, skipValidation, } = args;
27
+ const { forceCreate, message, derivedAccountId, skipValidation, formatOutputAsJson, profile, } = args;
28
+ const jsonOutput = {};
27
29
  const { projectConfig, projectDir } = await (0, config_2.getProjectConfig)();
28
30
  (0, config_2.validateProjectConfig)(projectConfig, projectDir);
29
- let targetAccountId = providedAccountId;
30
- if (!targetAccountId && (0, buildAndDeploy_1.useV3Api)(projectConfig.platformVersion)) {
31
- if (args.profile) {
32
- (0, projectProfiles_1.logProfileHeader)(args.profile);
33
- const profile = (0, projectProfiles_1.loadProfile)(projectConfig, projectDir, args.profile);
34
- if (!profile) {
35
- (0, ui_1.uiLine)();
36
- process.exit(exitCodes_1.EXIT_CODES.ERROR);
37
- }
38
- targetAccountId = profile.accountId;
39
- (0, projectProfiles_1.logProfileFooter)(profile, true);
40
- }
41
- else {
42
- // A profile must be specified if this project has profiles configured
43
- await (0, projectProfiles_1.exitIfUsingProfiles)(projectConfig, projectDir);
44
- }
45
- }
46
- if (!targetAccountId) {
47
- // The user is not using profiles, so we can use the derived accountId
48
- targetAccountId = derivedAccountId;
31
+ let targetAccountId;
32
+ if ((0, buildAndDeploy_1.useV3Api)(projectConfig.platformVersion)) {
33
+ targetAccountId = await (0, projectProfiles_1.loadAndValidateProfile)(projectConfig, projectDir, profile);
49
34
  }
35
+ targetAccountId = targetAccountId || derivedAccountId;
50
36
  const accountConfig = (0, config_1.getAccountConfig)(targetAccountId);
51
37
  const accountType = accountConfig && accountConfig.accountType;
52
38
  (0, usageTracking_1.trackCommandUsage)('project-upload', { type: accountType }, targetAccountId);
@@ -88,7 +74,12 @@ async function handler(args) {
88
74
  }));
89
75
  (0, ui_2.logFeedbackMessage)(result.buildId);
90
76
  await (0, buildAndDeploy_2.displayWarnLogs)(targetAccountId, projectConfig.name, result.buildId);
91
- process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
77
+ }
78
+ if (result && result.succeeded && formatOutputAsJson) {
79
+ jsonOutput.buildId = result.buildId;
80
+ if (result.deployResult) {
81
+ jsonOutput.deployId = result.deployResult.deployId;
82
+ }
92
83
  }
93
84
  }
94
85
  catch (e) {
@@ -98,6 +89,9 @@ async function handler(args) {
98
89
  }));
99
90
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
100
91
  }
92
+ if (formatOutputAsJson) {
93
+ logger_2.uiLogger.json(jsonOutput);
94
+ }
101
95
  process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
102
96
  }
103
97
  function projectUploadBuilder(yargs) {
@@ -139,6 +133,7 @@ const builder = (0, yargsUtils_1.makeYargsBuilder)(projectUploadBuilder, command
139
133
  useConfigOptions: true,
140
134
  useAccountOptions: true,
141
135
  useEnvironmentOptions: true,
136
+ useJSONOutputOptions: true,
142
137
  });
143
138
  const projectUploadCommand = {
144
139
  command,
@@ -0,0 +1,6 @@
1
+ import { CommonArgs, YargsCommandModule } from '../../types/Yargs';
2
+ type ProjectValidateArgs = CommonArgs & {
3
+ profile?: string;
4
+ };
5
+ declare const projectValidateCommand: YargsCommandModule<unknown, ProjectValidateArgs>;
6
+ export default projectValidateCommand;
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const path_1 = __importDefault(require("path"));
7
+ const config_1 = require("@hubspot/local-dev-lib/config");
8
+ const buildAndDeploy_1 = require("../../lib/projects/buildAndDeploy");
9
+ const usageTracking_1 = require("../../lib/usageTracking");
10
+ const logger_1 = require("../../lib/ui/logger");
11
+ const config_2 = require("../../lib/projects/config");
12
+ const exitCodes_1 = require("../../lib/enums/exitCodes");
13
+ const yargsUtils_1 = require("../../lib/yargsUtils");
14
+ const upload_1 = require("../../lib/projects/upload");
15
+ const en_1 = require("../../lang/en");
16
+ const projectProfiles_1 = require("../../lib/projectProfiles");
17
+ const errorHandlers_1 = require("../../lib/errorHandlers");
18
+ const command = 'validate';
19
+ const describe = undefined;
20
+ async function handler(args) {
21
+ const { derivedAccountId, profile } = args;
22
+ const { projectConfig, projectDir } = await (0, config_2.getProjectConfig)();
23
+ if (!projectConfig) {
24
+ logger_1.uiLogger.error(en_1.commands.project.validate.mustBeRanWithinAProject);
25
+ process.exit(exitCodes_1.EXIT_CODES.ERROR);
26
+ }
27
+ if (!(0, buildAndDeploy_1.useV3Api)(projectConfig?.platformVersion)) {
28
+ logger_1.uiLogger.error(en_1.commands.project.validate.badVersion);
29
+ process.exit(exitCodes_1.EXIT_CODES.ERROR);
30
+ }
31
+ (0, config_2.validateProjectConfig)(projectConfig, projectDir);
32
+ let targetAccountId = await (0, projectProfiles_1.loadAndValidateProfile)(projectConfig, projectDir, profile);
33
+ targetAccountId = targetAccountId || derivedAccountId;
34
+ const accountConfig = (0, config_1.getAccountConfig)(targetAccountId);
35
+ const accountType = accountConfig && accountConfig.accountType;
36
+ (0, usageTracking_1.trackCommandUsage)('project-validate', { type: accountType }, targetAccountId);
37
+ const srcDir = path_1.default.resolve(projectDir, projectConfig.srcDir);
38
+ try {
39
+ (0, upload_1.validateSourceDirectory)(srcDir, projectConfig);
40
+ }
41
+ catch (e) {
42
+ (0, errorHandlers_1.logError)(e);
43
+ process.exit(exitCodes_1.EXIT_CODES.ERROR);
44
+ }
45
+ try {
46
+ await (0, upload_1.handleTranslate)(projectDir, projectConfig, targetAccountId, false, profile);
47
+ }
48
+ catch (e) {
49
+ (0, errorHandlers_1.logError)(e);
50
+ process.exit(exitCodes_1.EXIT_CODES.ERROR);
51
+ }
52
+ logger_1.uiLogger.success(en_1.commands.project.validate.success(projectConfig.name));
53
+ process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
54
+ }
55
+ function projectValidateBuilder(yargs) {
56
+ yargs.options({
57
+ profile: {
58
+ type: 'string',
59
+ alias: 'p',
60
+ describe: en_1.commands.project.validate.options.profile.describe,
61
+ hidden: true,
62
+ },
63
+ });
64
+ yargs.conflicts('profile', 'account');
65
+ yargs.example([
66
+ ['$0 project validate', en_1.commands.project.validate.examples.default],
67
+ ]);
68
+ return yargs;
69
+ }
70
+ const builder = (0, yargsUtils_1.makeYargsBuilder)(projectValidateBuilder, command, describe, {
71
+ useGlobalOptions: true,
72
+ useConfigOptions: true,
73
+ useAccountOptions: true,
74
+ useEnvironmentOptions: true,
75
+ });
76
+ const projectValidateCommand = {
77
+ command,
78
+ describe,
79
+ handler,
80
+ builder,
81
+ };
82
+ exports.default = projectValidateCommand;
@@ -20,6 +20,7 @@ const migrateApp_1 = __importDefault(require("./project/migrateApp"));
20
20
  const cloneApp_1 = __importDefault(require("./project/cloneApp"));
21
21
  const installDeps_1 = __importDefault(require("./project/installDeps"));
22
22
  const profile_1 = __importDefault(require("./project/profile"));
23
+ const validate_1 = __importDefault(require("./project/validate"));
23
24
  const yargsUtils_1 = require("../lib/yargsUtils");
24
25
  const command = ['project', 'projects'];
25
26
  const describe = (0, ui_1.uiBetaTag)((0, lang_1.i18n)(`commands.project.describe`), false);
@@ -40,6 +41,7 @@ function projectBuilder(yargs) {
40
41
  .command(cloneApp_1.default)
41
42
  .command(installDeps_1.default)
42
43
  .command(profile_1.default)
44
+ .command(validate_1.default)
43
45
  .demandCommand(1, '');
44
46
  return yargs;
45
47
  }