@hubspot/cli 8.14.0-beta.1 → 8.15.0-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 (91) hide show
  1. package/commands/cms/theme/preview.js +8 -1
  2. package/commands/getStarted.js +15 -20
  3. package/commands/project/add.js +7 -6
  4. package/commands/project/appInstallStatus.d.ts +1 -1
  5. package/commands/project/appInstallStatus.js +8 -4
  6. package/commands/project/create.js +20 -6
  7. package/commands/project/delete.js +1 -1
  8. package/commands/project/deploy.d.ts +1 -1
  9. package/commands/project/deploy.js +14 -12
  10. package/commands/project/dev/index.js +4 -7
  11. package/commands/project/download.js +3 -3
  12. package/commands/project/info.d.ts +1 -1
  13. package/commands/project/info.js +8 -5
  14. package/commands/project/installApp.d.ts +1 -1
  15. package/commands/project/installApp.js +9 -4
  16. package/commands/project/installDeps.js +6 -5
  17. package/commands/project/lint.js +16 -9
  18. package/commands/project/list.d.ts +3 -2
  19. package/commands/project/list.js +21 -3
  20. package/commands/project/listBuilds.d.ts +1 -1
  21. package/commands/project/listBuilds.js +4 -8
  22. package/commands/project/migrate.js +14 -12
  23. package/commands/project/open.js +15 -7
  24. package/commands/project/profile/add.js +8 -4
  25. package/commands/project/profile/delete.js +8 -4
  26. package/commands/project/release/create.d.ts +1 -1
  27. package/commands/project/release/create.js +5 -7
  28. package/commands/project/release/info.d.ts +1 -1
  29. package/commands/project/release/info.js +4 -4
  30. package/commands/project/release/list.d.ts +1 -1
  31. package/commands/project/release/list.js +4 -4
  32. package/commands/project/updateDeps.js +6 -5
  33. package/commands/project/upload.d.ts +1 -1
  34. package/commands/project/upload.js +26 -15
  35. package/commands/project/validate.js +14 -97
  36. package/commands/project/watch.js +8 -11
  37. package/commands/project.js +1 -1
  38. package/commands/testAccount/create.d.ts +1 -1
  39. package/commands/testAccount/create.js +1 -1
  40. package/lang/en.d.ts +7 -18
  41. package/lang/en.js +7 -18
  42. package/lib/app/migrate.js +5 -7
  43. package/lib/dependencyManagement.js +3 -10
  44. package/lib/doctor/DiagnosticInfoBuilder.d.ts +2 -2
  45. package/lib/doctor/DiagnosticInfoBuilder.js +8 -8
  46. package/lib/doctor/Doctor.js +7 -9
  47. package/lib/errors/ProjectErrors.d.ts +0 -6
  48. package/lib/errors/ProjectErrors.js +0 -12
  49. package/lib/errors/ProjectValidationError.d.ts +2 -1
  50. package/lib/errors/ProjectValidationError.js +3 -1
  51. package/lib/getStartedV2Actions.js +14 -18
  52. package/lib/jsonOutput/appInstallStatus.d.ts +14 -0
  53. package/lib/jsonOutput/appInstallStatus.js +14 -0
  54. package/lib/jsonOutput/createTestAccount.d.ts +7 -0
  55. package/lib/jsonOutput/createTestAccount.js +6 -0
  56. package/lib/jsonOutput/deploy.d.ts +5 -0
  57. package/lib/jsonOutput/deploy.js +4 -0
  58. package/lib/jsonOutput/info.d.ts +21 -0
  59. package/lib/jsonOutput/info.js +19 -0
  60. package/lib/jsonOutput/installApp.d.ts +11 -0
  61. package/lib/jsonOutput/installApp.js +10 -0
  62. package/lib/jsonOutput/listBuilds.d.ts +75 -0
  63. package/lib/jsonOutput/listBuilds.js +65 -0
  64. package/lib/jsonOutput/projectList.d.ts +29 -0
  65. package/lib/jsonOutput/projectList.js +28 -0
  66. package/lib/jsonOutput/release.d.ts +42 -0
  67. package/lib/jsonOutput/release.js +37 -0
  68. package/lib/jsonOutput/upload.d.ts +29 -0
  69. package/lib/jsonOutput/upload.js +23 -0
  70. package/lib/npm/packageJson.js +1 -1
  71. package/lib/projects/ProjectLogsManager.js +1 -4
  72. package/lib/projects/config.d.ts +6 -5
  73. package/lib/projects/config.js +7 -38
  74. package/lib/projects/create/tracking.d.ts +1 -0
  75. package/lib/projects/create/tracking.js +27 -0
  76. package/lib/projects/delete.js +14 -1
  77. package/lib/projects/localDev/LocalDevProcess.js +7 -7
  78. package/lib/projects/projectProfiles.d.ts +2 -2
  79. package/lib/projects/projectProfiles.js +0 -3
  80. package/lib/projects/release.js +1 -1
  81. package/lib/projects/uieLinting.js +0 -3
  82. package/lib/projects/validate.d.ts +9 -0
  83. package/lib/projects/validate.js +96 -0
  84. package/lib/theme/migrate.js +1 -4
  85. package/mcp-server/tools/project/GetBuildLogsTool.js +2 -3
  86. package/mcp-server/tools/project/GetBuildStatusTool.js +2 -3
  87. package/mcp-server/tools/project/UploadProjectTools.js +3 -5
  88. package/package.json +3 -3
  89. package/types/Projects.d.ts +1 -5
  90. package/lib/jsonOutput.d.ts +0 -182
  91. package/lib/jsonOutput.js +0 -158
@@ -1,7 +1,7 @@
1
1
  import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
2
2
  import { fetchProject, fetchProjectBuilds, } from '@hubspot/local-dev-lib/api/projects';
3
3
  import { uiLink } from '../../lib/ui/index.js';
4
- import { getProjectConfig, validateProjectConfig, } from '../../lib/projects/config.js';
4
+ import { getProjectConfig } from '../../lib/projects/config.js';
5
5
  import { getProjectDetailUrl } from '../../lib/projects/urls.js';
6
6
  import moment from 'moment';
7
7
  import { promptUser } from '../../lib/prompts/promptUtils.js';
@@ -13,7 +13,7 @@ import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
13
13
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
14
14
  import { commands } from '../../lang/en.js';
15
15
  import { renderTable } from '../../ui/render.js';
16
- import { ProjectBuildsListSchema, mapBuildToJsonOutput, } from '../../lib/jsonOutput.js';
16
+ import { ProjectBuildsListSchema, mapBuildToJsonOutput, } from '../../lib/jsonOutput/listBuilds.js';
17
17
  const command = 'list-builds';
18
18
  const describe = commands.project.listBuilds.describe;
19
19
  async function fetchAndDisplayBuilds(accountId, project, options) {
@@ -66,18 +66,14 @@ async function handler(args) {
66
66
  const { project: projectFlagValue, limit, derivedAccountId, exit, json: formatOutputAsJson, addJsonOutput, } = args;
67
67
  let projectName = projectFlagValue;
68
68
  if (!projectName) {
69
- const { projectConfig, projectDir } = await getProjectConfig();
70
69
  try {
71
- validateProjectConfig(projectConfig, projectDir);
70
+ const { projectConfig } = getProjectConfig();
71
+ projectName = projectConfig.name;
72
72
  }
73
73
  catch (error) {
74
74
  logError(error);
75
75
  return exit(EXIT_CODES.ERROR);
76
76
  }
77
- if (!projectConfig) {
78
- return exit(EXIT_CODES.ERROR);
79
- }
80
- projectName = projectConfig.name;
81
77
  }
82
78
  try {
83
79
  const { data: project } = await fetchProject(derivedAccountId, projectName);
@@ -19,19 +19,21 @@ const command = 'migrate';
19
19
  const describe = commands.project.migrate.describe;
20
20
  async function handler(args) {
21
21
  const { platformVersion, unstable, derivedAccountId, exit } = args;
22
- const projectConfig = await getProjectConfig();
23
- if (!projectConfig.projectConfig) {
22
+ let projectConfig;
23
+ let projectDir;
24
+ try {
25
+ ({ projectConfig, projectDir } = getProjectConfig());
26
+ }
27
+ catch {
24
28
  uiLogger.error(commands.project.migrate.errors.noProjectConfig(uiCommandReference('hs app migrate')));
25
29
  return exit(EXIT_CODES.ERROR);
26
30
  }
27
- if (projectConfig?.projectConfig) {
28
- await renderInline(getWarningBox({
29
- title: lib.migrate.projectMigrationWarningTitle(platformVersion),
30
- message: lib.migrate.projectMigrationWarning(platformVersion),
31
- }));
32
- }
31
+ await renderInline(getWarningBox({
32
+ title: lib.migrate.projectMigrationWarningTitle(platformVersion),
33
+ message: lib.migrate.projectMigrationWarning(platformVersion),
34
+ }));
33
35
  try {
34
- const { hasMigratableThemes, migratableThemesCount } = await getHasMigratableThemes(projectConfig);
36
+ const { hasMigratableThemes, migratableThemesCount } = await getHasMigratableThemes({ projectConfig, projectDir });
35
37
  if (hasMigratableThemes) {
36
38
  const hasThemeMigrationAccess = await hasFeature(derivedAccountId, FEATURES.THEME_MIGRATION_2025_2);
37
39
  if (!hasThemeMigrationAccess) {
@@ -43,16 +45,16 @@ async function handler(args) {
43
45
  platformVersion: unstable
44
46
  ? PLATFORM_VERSIONS.UNSTABLE
45
47
  : platformVersion,
46
- }, migratableThemesCount, projectConfig);
48
+ }, migratableThemesCount, { projectConfig, projectDir });
47
49
  }
48
50
  else {
49
51
  await migrateApp(derivedAccountId, {
50
52
  ...args,
51
- name: projectConfig?.projectConfig?.name,
53
+ name: projectConfig.name,
52
54
  platformVersion: unstable
53
55
  ? PLATFORM_VERSIONS.UNSTABLE
54
56
  : platformVersion,
55
- }, projectConfig);
57
+ }, { projectConfig, projectDir });
56
58
  }
57
59
  }
58
60
  catch (error) {
@@ -12,7 +12,6 @@ const command = 'open';
12
12
  const describe = commands.project.open.describe;
13
13
  async function handler(args) {
14
14
  const { project, derivedAccountId, exit } = args;
15
- const { projectConfig } = await getProjectConfig();
16
15
  let projectName = project;
17
16
  if (projectName) {
18
17
  const { projectExists } = await ensureProjectExists(derivedAccountId, projectName, {
@@ -22,12 +21,21 @@ async function handler(args) {
22
21
  return exit(EXIT_CODES.ERROR);
23
22
  }
24
23
  }
25
- else if (!projectName && projectConfig) {
26
- projectName = projectConfig.name;
27
- }
28
- else if (!projectName && !projectConfig) {
29
- const namePromptResponse = await projectNamePrompt(derivedAccountId);
30
- projectName = namePromptResponse.projectName;
24
+ else if (!projectName) {
25
+ let projectConfig;
26
+ try {
27
+ ({ projectConfig } = getProjectConfig());
28
+ }
29
+ catch {
30
+ // Not in a project directory, fall through to prompt
31
+ }
32
+ if (projectConfig) {
33
+ projectName = projectConfig.name;
34
+ }
35
+ else {
36
+ const namePromptResponse = await projectNamePrompt(derivedAccountId);
37
+ projectName = namePromptResponse.projectName;
38
+ }
31
39
  }
32
40
  const url = getProjectDetailUrl(projectName, derivedAccountId);
33
41
  open(url, { url: true });
@@ -12,7 +12,7 @@ import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
12
12
  import { commands } from '../../../lang/en.js';
13
13
  import { promptUser, listPrompt, confirmPrompt, } from '../../../lib/prompts/promptUtils.js';
14
14
  import { fileExists } from '../../../lib/validation.js';
15
- import { debugError } from '../../../lib/errorHandlers/index.js';
15
+ import { debugError, logError } from '../../../lib/errorHandlers/index.js';
16
16
  const command = 'add [name]';
17
17
  const describe = commands.project.profile.add.describe;
18
18
  const verboseDescribe = commands.project.profile.add.verboseDescribe;
@@ -52,9 +52,13 @@ async function selectProfileToCopyVariablesFrom(existingProfiles) {
52
52
  }
53
53
  async function handler(args) {
54
54
  const { exit } = args;
55
- const { projectConfig, projectDir } = await getProjectConfig();
56
- if (!projectConfig || !projectDir) {
57
- uiLogger.error(commands.project.profile.add.errors.noProjectConfig);
55
+ let projectConfig;
56
+ let projectDir;
57
+ try {
58
+ ({ projectConfig, projectDir } = getProjectConfig());
59
+ }
60
+ catch (error) {
61
+ logError(error);
58
62
  return exit(EXIT_CODES.ERROR);
59
63
  }
60
64
  if (isLegacyProject(projectConfig.platformVersion)) {
@@ -12,15 +12,19 @@ import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
12
12
  import { commands } from '../../../lang/en.js';
13
13
  import { confirmPrompt, listPrompt } from '../../../lib/prompts/promptUtils.js';
14
14
  import { fileExists } from '../../../lib/validation.js';
15
- import { debugError } from '../../../lib/errorHandlers/index.js';
15
+ import { debugError, logError } from '../../../lib/errorHandlers/index.js';
16
16
  import { isDeveloperTestAccount, isSandbox, } from '../../../lib/accountTypes.js';
17
17
  const command = 'delete [name]';
18
18
  const describe = commands.project.profile.delete.describe;
19
19
  async function handler(args) {
20
20
  const { exit } = args;
21
- const { projectConfig, projectDir } = await getProjectConfig();
22
- if (!projectConfig || !projectDir) {
23
- uiLogger.error(commands.project.profile.delete.errors.noProjectConfig);
21
+ let projectConfig;
22
+ let projectDir;
23
+ try {
24
+ ({ projectConfig, projectDir } = getProjectConfig());
25
+ }
26
+ catch (error) {
27
+ logError(error);
24
28
  return exit(EXIT_CODES.ERROR);
25
29
  }
26
30
  if (isLegacyProject(projectConfig.platformVersion)) {
@@ -1,5 +1,5 @@
1
1
  import { CommonArgs, ConfigArgs, AccountArgs, EnvironmentArgs, JSONOutputArgs, YargsCommandModule } from '../../../types/Yargs.js';
2
- import { ReleaseJsonOutput } from '../../../lib/jsonOutput.js';
2
+ import { ReleaseJsonOutput } from '../../../lib/jsonOutput/release.js';
3
3
  export type ProjectReleaseCreateArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs<ReleaseJsonOutput> & {
4
4
  build?: number;
5
5
  force: boolean;
@@ -3,14 +3,14 @@ import { pollProjectBuildAndDeploy } from '../../../lib/projects/pollProjectBuil
3
3
  import { resolveBuildId, validateBuildForRelease, executeRelease, } from '../../../lib/projects/release.js';
4
4
  import { logError, ApiErrorContext } from '../../../lib/errorHandlers/index.js';
5
5
  import { isPromptExitError } from '../../../lib/errors/PromptExitError.js';
6
- import { getProjectConfig, validateProjectConfig, } from '../../../lib/projects/config.js';
6
+ import { getProjectConfig } from '../../../lib/projects/config.js';
7
7
  import { confirmPrompt } from '../../../lib/prompts/promptUtils.js';
8
8
  import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
9
9
  import { uiLogger } from '../../../lib/ui/logger.js';
10
10
  import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
11
11
  import { commands } from '../../../lang/en.js';
12
12
  import { makeWrappedYargsHandler } from '../../../lib/yargs/makeWrappedYargsHandler.js';
13
- import { ReleaseSchema, mapReleaseToJsonOutput, } from '../../../lib/jsonOutput.js';
13
+ import { ReleaseSchema, mapReleaseToJsonOutput, } from '../../../lib/jsonOutput/release.js';
14
14
  const command = 'create';
15
15
  // const describe = commands.project.release.create.describe;
16
16
  const describe = undefined;
@@ -27,17 +27,15 @@ function logUploadError(error, accountId) {
27
27
  }
28
28
  async function handler(args) {
29
29
  const { exit, derivedAccountId, build: buildOption, json: formatOutputAsJson, force, addJsonOutput, } = args;
30
- const { projectConfig, projectDir } = await getProjectConfig();
30
+ let projectConfig;
31
+ let projectDir;
31
32
  try {
32
- validateProjectConfig(projectConfig, projectDir);
33
+ ({ projectConfig, projectDir } = getProjectConfig());
33
34
  }
34
35
  catch (error) {
35
36
  logError(error);
36
37
  return exit(EXIT_CODES.ERROR);
37
38
  }
38
- if (!projectConfig || !projectDir) {
39
- return exit(EXIT_CODES.ERROR);
40
- }
41
39
  const projectName = projectConfig.name;
42
40
  let buildId;
43
41
  try {
@@ -1,5 +1,5 @@
1
1
  import { CommonArgs, ConfigArgs, AccountArgs, EnvironmentArgs, JSONOutputArgs, YargsCommandModule } from '../../../types/Yargs.js';
2
- import { ReleaseJsonOutput } from '../../../lib/jsonOutput.js';
2
+ import { ReleaseJsonOutput } from '../../../lib/jsonOutput/release.js';
3
3
  export type ProjectReleaseInfoArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs<ReleaseJsonOutput> & {
4
4
  tag?: string;
5
5
  };
@@ -1,7 +1,7 @@
1
1
  import { getReleaseInfo, listReleases } from '../../../api/releases.js';
2
2
  import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
3
3
  import { logError, ApiErrorContext } from '../../../lib/errorHandlers/index.js';
4
- import { getProjectConfig, validateProjectConfig, } from '../../../lib/projects/config.js';
4
+ import { getProjectConfig } from '../../../lib/projects/config.js';
5
5
  import { listPrompt } from '../../../lib/prompts/promptUtils.js';
6
6
  import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
7
7
  import { uiLogger } from '../../../lib/ui/logger.js';
@@ -12,7 +12,7 @@ import { makeWrappedYargsHandler } from '../../../lib/yargs/makeWrappedYargsHand
12
12
  import { isPromptExitError } from '../../../lib/errors/PromptExitError.js';
13
13
  import { mapToUserFacingType } from '@hubspot/project-parsing-lib/transform';
14
14
  import { AUTO_GENERATED_COMPONENT_TYPES } from '@hubspot/project-parsing-lib/constants';
15
- import { ReleaseSchema, mapReleaseToJsonOutput, } from '../../../lib/jsonOutput.js';
15
+ import { ReleaseSchema, mapReleaseToJsonOutput, } from '../../../lib/jsonOutput/release.js';
16
16
  const command = 'info';
17
17
  // const describe = commands.project.release.info.describe;
18
18
  const describe = undefined;
@@ -38,9 +38,9 @@ async function selectReleasePrompt(accountId, projectName) {
38
38
  }
39
39
  async function handler(args) {
40
40
  const { derivedAccountId, tag: rawTag, json: formatOutputAsJson, exit, addJsonOutput, } = args;
41
- const { projectConfig, projectDir } = await getProjectConfig();
41
+ let projectConfig;
42
42
  try {
43
- validateProjectConfig(projectConfig, projectDir);
43
+ ({ projectConfig } = getProjectConfig());
44
44
  }
45
45
  catch (error) {
46
46
  logError(error);
@@ -1,5 +1,5 @@
1
1
  import { CommonArgs, ConfigArgs, AccountArgs, EnvironmentArgs, JSONOutputArgs, YargsCommandModule } from '../../../types/Yargs.js';
2
- import { ReleaseListJsonOutput } from '../../../lib/jsonOutput.js';
2
+ import { ReleaseListJsonOutput } from '../../../lib/jsonOutput/release.js';
3
3
  export type ProjectReleaseListArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs<ReleaseListJsonOutput> & {
4
4
  limit?: number;
5
5
  };
@@ -2,7 +2,7 @@ import { listReleases } from '../../../api/releases.js';
2
2
  import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
3
3
  import { isPromptExitError } from '../../../lib/errors/PromptExitError.js';
4
4
  import { logError, ApiErrorContext } from '../../../lib/errorHandlers/index.js';
5
- import { getProjectConfig, validateProjectConfig, } from '../../../lib/projects/config.js';
5
+ import { getProjectConfig } from '../../../lib/projects/config.js';
6
6
  import { promptUser } from '../../../lib/prompts/promptUtils.js';
7
7
  import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
8
8
  import { uiLogger } from '../../../lib/ui/logger.js';
@@ -10,7 +10,7 @@ import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
10
10
  import { commands } from '../../../lang/en.js';
11
11
  import { renderTable } from '../../../ui/render.js';
12
12
  import { makeWrappedYargsHandler } from '../../../lib/yargs/makeWrappedYargsHandler.js';
13
- import { ReleaseListSchema, mapReleaseToJsonOutput, } from '../../../lib/jsonOutput.js';
13
+ import { ReleaseListSchema, mapReleaseToJsonOutput, } from '../../../lib/jsonOutput/release.js';
14
14
  const command = 'list';
15
15
  // const describe = commands.project.release.list.describe;
16
16
  const describe = undefined;
@@ -43,9 +43,9 @@ async function fetchAndDisplayReleases(accountId, projectName, options) {
43
43
  }
44
44
  async function handler(args) {
45
45
  const { derivedAccountId, limit, json: formatOutputAsJson, exit, addJsonOutput, } = args;
46
- const { projectConfig, projectDir } = await getProjectConfig();
46
+ let projectConfig;
47
47
  try {
48
- validateProjectConfig(projectConfig, projectDir);
48
+ ({ projectConfig } = getProjectConfig());
49
49
  }
50
50
  catch (error) {
51
51
  logError(error);
@@ -5,7 +5,6 @@ import { getProjectConfig } from '../../lib/projects/config.js';
5
5
  import { promptUser } from '../../lib/prompts/promptUtils.js';
6
6
  import path from 'path';
7
7
  import { commands } from '../../lang/en.js';
8
- import { uiLogger } from '../../lib/ui/logger.js';
9
8
  import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler.js';
10
9
  import { logError } from '../../lib/errorHandlers/index.js';
11
10
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
@@ -14,12 +13,14 @@ const describe = commands.project.updateDeps.help.describe;
14
13
  async function handler(args) {
15
14
  const { packages, exit } = args;
16
15
  try {
17
- const projectConfig = await getProjectConfig();
18
- if (!projectConfig || !projectConfig.projectDir) {
19
- uiLogger.error(commands.project.updateDeps.noProjectConfig);
16
+ let projectDir;
17
+ try {
18
+ ({ projectDir } = getProjectConfig());
19
+ }
20
+ catch (error) {
21
+ logError(error);
20
22
  return exit(EXIT_CODES.ERROR);
21
23
  }
22
- const { projectDir } = projectConfig;
23
24
  let installLocations = await getProjectPackageJsonLocations();
24
25
  if (packages) {
25
26
  const { selectedInstallLocations } = await promptUser([
@@ -1,5 +1,5 @@
1
1
  import { CommonArgs, JSONOutputArgs, YargsCommandModule } from '../../types/Yargs.js';
2
- import { UploadJsonOutput } from '../../lib/jsonOutput.js';
2
+ import { UploadJsonOutput } from '../../lib/jsonOutput/upload.js';
3
3
  export type ProjectUploadArgs = CommonArgs & JSONOutputArgs<UploadJsonOutput> & {
4
4
  force: boolean;
5
5
  forceCreate: boolean;
@@ -3,7 +3,7 @@ import { uiLogger } from '../../lib/ui/logger.js';
3
3
  import { getConfigAccountById } from '@hubspot/local-dev-lib/config';
4
4
  import { isSpecifiedError } from '@hubspot/local-dev-lib/errors/index';
5
5
  import { isLegacyProject, meetsMinimumPlatformVersion, } from '@hubspot/project-parsing-lib/projects';
6
- import { getProjectConfig, validateProjectConfig, } from '../../lib/projects/config.js';
6
+ import { getProjectConfig } from '../../lib/projects/config.js';
7
7
  import { logFeedbackMessage } from '../../lib/projects/ui.js';
8
8
  import { handleProjectUpload } from '../../lib/projects/upload.js';
9
9
  import { loadAndValidateProfile } from '../../lib/projects/projectProfiles.js';
@@ -14,7 +14,7 @@ import { PROJECT_ERROR_TYPES } from '../../lib/constants.js';
14
14
  import { logError, ApiErrorContext } from '../../lib/errorHandlers/index.js';
15
15
  import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
16
16
  import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler.js';
17
- import { UploadSchema, } from '../../lib/jsonOutput.js';
17
+ import { mapAccountToTargetAccount, UploadSchema, } from '../../lib/jsonOutput/upload.js';
18
18
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
19
19
  import { projectProfilePrompt } from '../../lib/prompts/projectProfilePrompt.js';
20
20
  import { uiDeprecatedTag } from '../../lib/ui/index.js';
@@ -41,27 +41,28 @@ async function handler(args) {
41
41
  if (forceCreate) {
42
42
  uiDeprecatedTag(commands.project.upload.logs.forceCreateDeprecated);
43
43
  }
44
- const { projectConfig, projectDir } = await getProjectConfig();
44
+ let projectConfig;
45
+ let projectDir;
45
46
  try {
46
- validateProjectConfig(projectConfig, projectDir);
47
+ ({ projectConfig, projectDir } = getProjectConfig());
47
48
  }
48
49
  catch (error) {
49
50
  logError(error);
50
51
  return exit(EXIT_CODES.ERROR);
51
52
  }
52
- if (!projectDir) {
53
- uiLogger.error(commands.project.upload.errors.noProjectConfig);
54
- return exit(EXIT_CODES.ERROR);
55
- }
56
53
  let targetAccountId;
57
54
  let profileName = args.profile;
58
- if (!isLegacyProject(projectConfig?.platformVersion)) {
55
+ let resolvedViaProfile = false;
56
+ if (!isLegacyProject(projectConfig.platformVersion)) {
59
57
  try {
60
58
  const profileNamePromptResult = await projectProfilePrompt(projectDir, projectConfig, profileOption, !!useEnvOption);
61
59
  if (profileNamePromptResult) {
62
60
  profileName = profileNamePromptResult;
63
61
  const profile = await loadAndValidateProfile(projectConfig, projectDir, profileName);
64
62
  targetAccountId = profile.accountId;
63
+ resolvedViaProfile = true;
64
+ uiLogger.log(commands.project.upload.logs.uploadingWithProfile(profileName, targetAccountId));
65
+ uiLogger.log('');
65
66
  }
66
67
  }
67
68
  catch (error) {
@@ -76,6 +77,10 @@ async function handler(args) {
76
77
  type: accountType,
77
78
  assetType: projectConfig.platformVersion,
78
79
  });
80
+ if (!resolvedViaProfile) {
81
+ uiLogger.log(commands.project.upload.logs.uploadingToAccount(targetAccountId));
82
+ uiLogger.log('');
83
+ }
79
84
  try {
80
85
  const { result, uploadError, projectId, userDeclined } = await handleProjectUpload({
81
86
  accountId: targetAccountId,
@@ -118,7 +123,7 @@ async function handler(args) {
118
123
  (!result.buildResult.isAutoDeployEnabled || preview || skipAutoDeploy)) {
119
124
  uiLogger.log(chalk.bold(commands.project.upload.logs.buildSucceeded(result.buildId)));
120
125
  if (!preview) {
121
- if (meetsMinimumPlatformVersion(result.buildResult.platformVersion, PLATFORM_VERSIONS.v2027_03_BETA)) {
126
+ if (meetsMinimumPlatformVersion(result.buildResult.platformVersion, PLATFORM_VERSIONS.v2027_03)) {
122
127
  const releaseCommand = `hs project release create --build=${result.buildId}`;
123
128
  uiLogger.log(commands.project.upload.logs.releaseManagementRequired(releaseCommand));
124
129
  }
@@ -132,17 +137,23 @@ async function handler(args) {
132
137
  }
133
138
  await displayWarnLogs(targetAccountId, projectConfig.name, result.buildId);
134
139
  }
140
+ if (result) {
141
+ addJsonOutput({
142
+ targetAccount: mapAccountToTargetAccount(targetAccountId, accountConfig),
143
+ buildId: result.buildId,
144
+ });
145
+ if (result.deployResult) {
146
+ addJsonOutput({ deployId: result.deployResult.deployId });
147
+ }
148
+ }
135
149
  if (result && result.succeeded && preview && targetPortalId) {
136
150
  const previewJson = await handlePreview(targetAccountId, projectId, result.buildId, targetPortalId);
137
151
  if (previewJson) {
138
152
  addJsonOutput({ preview: previewJson });
139
153
  }
140
154
  }
141
- if (result) {
142
- addJsonOutput({ buildId: result.buildId });
143
- if (result.deployResult) {
144
- addJsonOutput({ deployId: result.deployResult.deployId });
145
- }
155
+ if (result && result.succeeded) {
156
+ uiLogger.log(commands.project.upload.logs.uploadedToAccount(targetAccountId));
146
157
  }
147
158
  if (result && !result.succeeded) {
148
159
  return exit(EXIT_CODES.ERROR);
@@ -1,112 +1,40 @@
1
- import path from 'path';
2
1
  import { getConfigAccountById } from '@hubspot/local-dev-lib/config';
3
2
  import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
4
3
  import { uiLogger } from '../../lib/ui/logger.js';
5
- import { getProjectConfig, validateProjectConfig, } from '../../lib/projects/config.js';
4
+ import { getProjectConfig } from '../../lib/projects/config.js';
6
5
  import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
7
6
  import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler.js';
8
7
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
9
- import { validateSourceDirectory, handleTranslate, } from '../../lib/projects/upload.js';
10
8
  import { commands } from '../../lang/en.js';
11
- import { validateProjectForProfile } from '../../lib/projects/projectProfiles.js';
12
9
  import { logError } from '../../lib/errorHandlers/index.js';
13
- import { getAllHsProfiles } from '@hubspot/project-parsing-lib/profiles';
14
- import SpinniesManager from '../../lib/ui/SpinniesManager.js';
10
+ import { validateProject } from '../../lib/projects/validate.js';
15
11
  const command = 'validate';
16
12
  const describe = commands.project.validate.describe;
17
13
  async function handler(args) {
18
14
  const { derivedAccountId, profile, exit, addUsageMetadata } = args;
19
- const { projectConfig, projectDir } = await getProjectConfig();
20
15
  const accountConfig = getConfigAccountById(derivedAccountId);
21
16
  const accountType = accountConfig && accountConfig.accountType;
22
17
  addUsageMetadata({ type: accountType });
23
- if (!projectConfig || !projectDir) {
24
- uiLogger.error(commands.project.validate.mustBeRanWithinAProject);
25
- return exit(EXIT_CODES.ERROR);
26
- }
27
- if (isLegacyProject(projectConfig.platformVersion)) {
28
- uiLogger.error(commands.project.validate.badVersion);
29
- return exit(EXIT_CODES.ERROR);
30
- }
18
+ let projectConfig;
19
+ let projectDir;
31
20
  try {
32
- validateProjectConfig(projectConfig, projectDir);
21
+ ({ projectConfig, projectDir } = getProjectConfig());
33
22
  }
34
23
  catch (error) {
35
24
  logError(error);
36
25
  return exit(EXIT_CODES.ERROR);
37
26
  }
38
- let validationSucceeded = true;
39
- const srcDir = path.resolve(projectDir, projectConfig.srcDir);
40
- const profiles = await getAllHsProfiles(path.join(projectDir, projectConfig.srcDir));
41
- // If a profile is specified, only validate that profile
42
- if (profile) {
43
- const validationErrors = await validateProjectForProfile({
44
- projectConfig,
45
- projectDir,
46
- profileName: profile,
47
- derivedAccountId,
48
- });
49
- if (validationErrors.length) {
50
- logValidationErrors(validationErrors);
51
- validationSucceeded = false;
52
- }
53
- }
54
- else if (profiles.length > 0) {
55
- // If no profile was specified and the project has profiles, validate all of them
56
- SpinniesManager.add('validatingAllProfiles', {
57
- text: commands.project.validate.spinners.validatingAllProfiles,
58
- });
59
- const errors = [];
60
- for (const profileName of profiles) {
61
- const validationErrors = await validateProjectForProfile({
62
- projectConfig,
63
- projectDir,
64
- profileName,
65
- derivedAccountId,
66
- indentSpinners: true,
67
- });
68
- if (validationErrors.length) {
69
- errors.push(...validationErrors);
70
- validationSucceeded = false;
71
- }
72
- }
73
- if (validationSucceeded) {
74
- SpinniesManager.succeed('validatingAllProfiles', {
75
- text: commands.project.validate.spinners.allProfilesValidationSucceeded,
76
- });
77
- }
78
- else {
79
- SpinniesManager.fail('validatingAllProfiles', {
80
- text: commands.project.validate.spinners.allProfilesValidationFailed,
81
- });
82
- }
83
- logValidationErrors(errors);
84
- }
85
- else if (profiles.length === 0) {
86
- // If the project has no profiles, validate the project without a profile
87
- try {
88
- await handleTranslate({
89
- projectDir: projectDir,
90
- projectConfig,
91
- accountId: derivedAccountId,
92
- skipValidation: false,
93
- });
94
- }
95
- catch (e) {
96
- uiLogger.error(commands.project.validate.failure(projectConfig.name));
97
- logError(e);
98
- validationSucceeded = false;
99
- uiLogger.log('');
100
- }
101
- }
102
- if (!validationSucceeded) {
27
+ if (isLegacyProject(projectConfig.platformVersion)) {
28
+ uiLogger.error(commands.project.validate.badVersion);
103
29
  return exit(EXIT_CODES.ERROR);
104
30
  }
105
- try {
106
- await validateSourceDirectory(srcDir, projectConfig, projectDir);
107
- }
108
- catch (e) {
109
- logError(e);
31
+ const valid = await validateProject({
32
+ projectConfig,
33
+ projectDir,
34
+ derivedAccountId,
35
+ profile,
36
+ });
37
+ if (!valid) {
110
38
  return exit(EXIT_CODES.ERROR);
111
39
  }
112
40
  uiLogger.success(commands.project.validate.success(projectConfig.name));
@@ -130,17 +58,6 @@ function projectValidateBuilder(yargs) {
130
58
  ]);
131
59
  return yargs;
132
60
  }
133
- function logValidationErrors(validationErrors) {
134
- uiLogger.log('');
135
- validationErrors.forEach(error => {
136
- if (error instanceof Error) {
137
- logError(error);
138
- }
139
- else {
140
- uiLogger.log(error);
141
- }
142
- });
143
- }
144
61
  const builder = makeYargsBuilder(projectValidateBuilder, command, describe, {
145
62
  useGlobalOptions: true,
146
63
  useConfigOptions: true,
@@ -6,7 +6,7 @@ import { createWatcher } from '../../lib/projects/watch.js';
6
6
  import { logError, ApiErrorContext } from '../../lib/errorHandlers/index.js';
7
7
  import { uiLogger } from '../../lib/ui/logger.js';
8
8
  import { PROJECT_ERROR_TYPES } from '../../lib/constants.js';
9
- import { getProjectConfig, validateProjectConfig, } from '../../lib/projects/config.js';
9
+ import { getProjectConfig } from '../../lib/projects/config.js';
10
10
  import { logFeedbackMessage } from '../../lib/projects/ui.js';
11
11
  import { handleProjectUpload } from '../../lib/projects/upload.js';
12
12
  import { pollBuildStatus, pollDeployStatus, } from '../../lib/projects/pollProjectBuildAndDeploy.js';
@@ -58,22 +58,19 @@ function handleUserInput(accountId, projectName, currentBuildId, exit) {
58
58
  async function handler(args) {
59
59
  const { initialUpload, derivedAccountId, exit } = args;
60
60
  uiCommandRelocatedMessage('hs project dev');
61
- const { projectConfig, projectDir } = await getProjectConfig();
62
- if (!projectConfig || !projectDir) {
63
- uiLogger.error(commands.project.watch.errors.projectConfigNotFound);
64
- return exit(EXIT_CODES.ERROR);
65
- }
66
- if (!isLegacyProject(projectConfig.platformVersion)) {
67
- uiLogger.error(commands.project.watch.errors.v2ApiError(projectConfig.platformVersion));
68
- return exit(EXIT_CODES.ERROR);
69
- }
61
+ let projectConfig;
62
+ let projectDir;
70
63
  try {
71
- validateProjectConfig(projectConfig, projectDir);
64
+ ({ projectConfig, projectDir } = getProjectConfig());
72
65
  }
73
66
  catch (error) {
74
67
  logError(error);
75
68
  return exit(EXIT_CODES.ERROR);
76
69
  }
70
+ if (!isLegacyProject(projectConfig.platformVersion)) {
71
+ uiLogger.error(commands.project.watch.errors.v2ApiError(projectConfig.platformVersion));
72
+ return exit(EXIT_CODES.ERROR);
73
+ }
77
74
  try {
78
75
  const { data: { results: builds }, } = await fetchProjectBuilds(derivedAccountId, projectConfig.name);
79
76
  const hasNoBuilds = !builds || !builds.length;
@@ -33,7 +33,7 @@ const describe = commands.project.describe;
33
33
  // the CLI is not officially compatible with
34
34
  async function validatePlatformVersion() {
35
35
  try {
36
- const { projectConfig } = await getProjectConfig();
36
+ const { projectConfig } = getProjectConfig();
37
37
  // Only warn if a platform version is explicitly set but not supported
38
38
  // Don't warn if the platform version is missing/undefined
39
39
  if (projectConfig?.platformVersion &&
@@ -1,6 +1,6 @@
1
1
  import { AccountLevel } from '@hubspot/local-dev-lib/types/developerTestAccounts.js';
2
2
  import { CommonArgs, ConfigArgs, AccountArgs, TestingArgs, EnvironmentArgs, JSONOutputArgs, YargsCommandModule } from '../../types/Yargs.js';
3
- import { CreateTestAccountJsonOutput } from '../../lib/jsonOutput.js';
3
+ import { CreateTestAccountJsonOutput } from '../../lib/jsonOutput/createTestAccount.js';
4
4
  type CreateTestAccountArgs = CommonArgs & AccountArgs & ConfigArgs & TestingArgs & EnvironmentArgs & JSONOutputArgs<CreateTestAccountJsonOutput> & {
5
5
  configPath?: string;
6
6
  name?: string;