@hubspot/cli 8.2.0-experimental.2 → 8.2.1-experimental.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 (147) hide show
  1. package/commands/account/clean.js +1 -1
  2. package/commands/account/list.js +1 -1
  3. package/commands/account/remove.js +1 -1
  4. package/commands/account/rename.js +1 -1
  5. package/commands/account/use.js +1 -1
  6. package/commands/api.d.ts +4 -1
  7. package/commands/api.js +11 -14
  8. package/commands/config/set.js +24 -5
  9. package/commands/customObject/createSchema.js +2 -3
  10. package/commands/customObject/updateSchema.js +2 -3
  11. package/commands/getStarted.js +1 -0
  12. package/commands/hubdb/list.d.ts +1 -1
  13. package/commands/hubdb/list.js +7 -8
  14. package/commands/mcp/setup.d.ts +2 -0
  15. package/commands/mcp/setup.js +29 -1
  16. package/commands/project/appInstallStatus.d.ts +2 -1
  17. package/commands/project/appInstallStatus.js +21 -19
  18. package/commands/project/create.js +0 -1
  19. package/commands/project/deploy.d.ts +2 -1
  20. package/commands/project/deploy.js +31 -14
  21. package/commands/project/dev/index.js +18 -64
  22. package/commands/project/dev/unifiedFlow.js +3 -1
  23. package/commands/project/info.d.ts +2 -1
  24. package/commands/project/info.js +8 -6
  25. package/commands/project/installApp.d.ts +2 -1
  26. package/commands/project/installApp.js +26 -27
  27. package/commands/project/list.js +1 -1
  28. package/commands/project/listBuilds.d.ts +1 -1
  29. package/commands/project/listBuilds.js +8 -6
  30. package/commands/project/logs.js +2 -4
  31. package/commands/project/profile/add.d.ts +2 -1
  32. package/commands/project/profile/add.js +22 -1
  33. package/commands/project/profile/delete.d.ts +1 -1
  34. package/commands/project/release/create.d.ts +2 -1
  35. package/commands/project/release/create.js +68 -69
  36. package/commands/project/release/info.d.ts +2 -1
  37. package/commands/project/release/info.js +7 -6
  38. package/commands/project/release/list.d.ts +2 -1
  39. package/commands/project/release/list.js +15 -7
  40. package/commands/project/upload.d.ts +4 -1
  41. package/commands/project/upload.js +48 -21
  42. package/commands/project/validate.d.ts +1 -1
  43. package/commands/project/watch.js +3 -2
  44. package/commands/project.js +2 -2
  45. package/commands/sandbox/delete.js +2 -3
  46. package/commands/testAccount/create.d.ts +2 -1
  47. package/commands/testAccount/create.js +7 -7
  48. package/commands/testAccount/importData.d.ts +1 -1
  49. package/lang/en.d.ts +61 -33
  50. package/lang/en.js +77 -48
  51. package/lib/app/urls.js +2 -3
  52. package/lib/commonOpts.js +6 -1
  53. package/lib/configOptions.d.ts +10 -10
  54. package/lib/configOptions.js +10 -11
  55. package/lib/constants.d.ts +2 -0
  56. package/lib/constants.js +2 -0
  57. package/lib/dependencyManagement.js +7 -7
  58. package/lib/getStartedV2Actions.js +2 -1
  59. package/lib/importData.js +3 -4
  60. package/lib/jsonOutput.d.ts +109 -0
  61. package/lib/jsonOutput.js +94 -0
  62. package/lib/links.js +6 -5
  63. package/lib/mcp/clients.d.ts +1 -1
  64. package/lib/mcp/clients.js +8 -1
  65. package/lib/mcp/setup.d.ts +9 -4
  66. package/lib/mcp/setup.js +115 -35
  67. package/lib/npm/npmCli.d.ts +1 -0
  68. package/lib/npm/npmCli.js +13 -0
  69. package/lib/projects/builds.d.ts +2 -0
  70. package/lib/projects/builds.js +22 -0
  71. package/lib/projects/create/v2.js +1 -0
  72. package/lib/projects/installApp.d.ts +1 -1
  73. package/lib/projects/installApp.js +8 -3
  74. package/lib/projects/localDev/DevSessionManager.d.ts +2 -2
  75. package/lib/projects/localDev/DevSessionManager.js +4 -30
  76. package/lib/projects/localDev/LocalDevProcess.js +7 -5
  77. package/lib/projects/localDev/helpers/account.d.ts +0 -7
  78. package/lib/projects/localDev/helpers/account.js +1 -80
  79. package/lib/projects/localDev/helpers/project.js +3 -2
  80. package/lib/projects/release.d.ts +4 -0
  81. package/lib/projects/release.js +90 -0
  82. package/lib/projects/ui.d.ts +1 -0
  83. package/lib/projects/ui.js +14 -0
  84. package/lib/projects/upload.d.ts +10 -2
  85. package/lib/projects/upload.js +14 -7
  86. package/lib/projects/urls.d.ts +0 -1
  87. package/lib/projects/urls.js +6 -13
  88. package/lib/yargs/makeWrappedYargsHandler.d.ts +5 -1
  89. package/lib/yargs/makeWrappedYargsHandler.js +123 -65
  90. package/mcp-server/Tool.d.ts +8 -3
  91. package/mcp-server/Tool.js +58 -32
  92. package/mcp-server/server.js +10 -6
  93. package/mcp-server/tools/cms/HsCreateFunctionTool.d.ts +2 -2
  94. package/mcp-server/tools/cms/HsCreateFunctionTool.js +10 -17
  95. package/mcp-server/tools/cms/HsCreateModuleTool.d.ts +2 -2
  96. package/mcp-server/tools/cms/HsCreateModuleTool.js +12 -18
  97. package/mcp-server/tools/cms/HsCreateTemplateTool.d.ts +2 -2
  98. package/mcp-server/tools/cms/HsCreateTemplateTool.js +8 -10
  99. package/mcp-server/tools/cms/HsFunctionLogsTool.d.ts +2 -2
  100. package/mcp-server/tools/cms/HsFunctionLogsTool.js +9 -9
  101. package/mcp-server/tools/cms/HsListFunctionsTool.d.ts +2 -2
  102. package/mcp-server/tools/cms/HsListFunctionsTool.js +7 -7
  103. package/mcp-server/tools/cms/HsListTool.d.ts +2 -2
  104. package/mcp-server/tools/cms/HsListTool.js +6 -10
  105. package/mcp-server/tools/index.js +2 -0
  106. package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +3 -2
  107. package/mcp-server/tools/project/AddFeatureToProjectTool.js +8 -9
  108. package/mcp-server/tools/project/AuthAccountTool.d.ts +18 -0
  109. package/mcp-server/tools/project/AuthAccountTool.js +78 -0
  110. package/mcp-server/tools/project/CreateProjectTool.d.ts +3 -2
  111. package/mcp-server/tools/project/CreateProjectTool.js +13 -12
  112. package/mcp-server/tools/project/CreateTestAccountTool.d.ts +2 -2
  113. package/mcp-server/tools/project/CreateTestAccountTool.js +14 -15
  114. package/mcp-server/tools/project/DeployProjectTool.d.ts +2 -2
  115. package/mcp-server/tools/project/DeployProjectTool.js +10 -10
  116. package/mcp-server/tools/project/DocFetchTool.js +1 -1
  117. package/mcp-server/tools/project/DocsSearchTool.js +8 -7
  118. package/mcp-server/tools/project/FindProjectsTool.js +1 -1
  119. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.d.ts +2 -1
  120. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +9 -8
  121. package/mcp-server/tools/project/GetApplicationInfoTool.d.ts +2 -1
  122. package/mcp-server/tools/project/GetApplicationInfoTool.js +12 -9
  123. package/mcp-server/tools/project/GetBuildLogsTool.js +11 -7
  124. package/mcp-server/tools/project/GetBuildStatusTool.js +11 -7
  125. package/mcp-server/tools/project/GetConfigValuesTool.d.ts +2 -1
  126. package/mcp-server/tools/project/GetConfigValuesTool.js +9 -7
  127. package/mcp-server/tools/project/GuidedWalkthroughTool.js +1 -1
  128. package/mcp-server/tools/project/UploadProjectTools.d.ts +2 -2
  129. package/mcp-server/tools/project/UploadProjectTools.js +9 -8
  130. package/mcp-server/tools/project/ValidateProjectTool.d.ts +2 -2
  131. package/mcp-server/tools/project/ValidateProjectTool.js +5 -4
  132. package/mcp-server/tools/project/constants.d.ts +1 -0
  133. package/mcp-server/tools/project/constants.js +2 -1
  134. package/mcp-server/utils/command.d.ts +25 -2
  135. package/mcp-server/utils/command.js +67 -17
  136. package/mcp-server/utils/config.js +5 -0
  137. package/mcp-server/utils/logger.d.ts +3 -0
  138. package/mcp-server/utils/logger.js +30 -0
  139. package/mcp-server/utils/toolUsageTracking.js +18 -3
  140. package/package.json +11 -9
  141. package/types/Yargs.d.ts +3 -1
  142. package/commands/project/dev/deprecatedFlow.d.ts +0 -11
  143. package/commands/project/dev/deprecatedFlow.js +0 -180
  144. package/lib/projects/localDev/DevServerManager_DEPRECATED.d.ts +0 -43
  145. package/lib/projects/localDev/DevServerManager_DEPRECATED.js +0 -128
  146. package/lib/projects/localDev/LocalDevManager_DEPRECATED.d.ts +0 -64
  147. package/lib/projects/localDev/LocalDevManager_DEPRECATED.js +0 -394
@@ -3,7 +3,6 @@ import { getProjectConfig, validateProjectConfig, } from '../../../lib/projects/
3
3
  import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
4
4
  import { uiLine } from '../../../lib/ui/index.js';
5
5
  import { makeWrappedYargsHandler } from '../../../lib/yargs/makeWrappedYargsHandler.js';
6
- import { deprecatedProjectDevFlow } from './deprecatedFlow.js';
7
6
  import { unifiedProjectDevFlow } from './unifiedFlow.js';
8
7
  import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
9
8
  import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
@@ -16,17 +15,8 @@ import { isPromptExitError } from '../../../lib/errors/PromptExitError.js';
16
15
  import { LOCAL_DEV_DEFAULT_PORT } from '../../../lib/constants.js';
17
16
  const command = 'dev';
18
17
  const describe = commands.project.dev.describe;
19
- function validateAccountFlags(testingAccount, projectAccount, userProvidedAccount, useV2) {
20
- // Legacy projects do not support targetTestingAccount and targetProjectAccount
21
- if (testingAccount && projectAccount && !useV2) {
22
- throw new Error(commands.project.dev.errors.unsupportedAccountFlagLegacy);
23
- }
24
- if (userProvidedAccount && useV2) {
25
- throw new Error(commands.project.dev.errors.unsupportedAccountFlagV2);
26
- }
27
- }
28
18
  async function handler(args) {
29
- const { derivedAccountId, userProvidedAccount, testingAccount, projectAccount, profile: profileOption, exit, addUsageMetadata, } = args;
19
+ const { derivedAccountId, testingAccount, projectAccount, profile: profileOption, exit, addUsageMetadata, } = args;
30
20
  const { projectConfig, projectDir } = await getProjectConfig();
31
21
  try {
32
22
  validateProjectConfig(projectConfig, projectDir);
@@ -35,28 +25,18 @@ async function handler(args) {
35
25
  logError(error);
36
26
  return exit(EXIT_CODES.ERROR);
37
27
  }
38
- const useV2Projects = !isLegacyProject(projectConfig.platformVersion);
39
28
  if (!projectDir) {
40
29
  uiLogger.error(commands.project.dev.errors.noProjectConfig);
41
30
  return exit(EXIT_CODES.ERROR);
42
31
  }
43
- try {
44
- validateAccountFlags(testingAccount, projectAccount, userProvidedAccount, useV2Projects);
45
- }
46
- catch (error) {
47
- logError(error);
32
+ if (isLegacyProject(projectConfig.platformVersion)) {
33
+ uiLogger.error(commands.project.dev.errors.unsupportedPlatformVersion(projectConfig.platformVersion));
48
34
  return exit(EXIT_CODES.ERROR);
49
35
  }
50
36
  uiLogger.log(commands.project.dev.logs.header);
51
- if (useV2Projects) {
52
- uiLogger.log(commands.project.dev.logs.learnMoreMessageV2);
53
- }
54
- else {
55
- uiLogger.log(commands.project.dev.logs.learnMoreMessageLegacy);
56
- }
37
+ uiLogger.log(commands.project.dev.logs.learnMoreMessageV2);
57
38
  let targetProjectAccountId;
58
39
  let profile;
59
- // Using the new --projectAccount flag
60
40
  if (projectAccount) {
61
41
  targetProjectAccountId =
62
42
  getConfigAccountIfExists(projectAccount)?.accountId;
@@ -64,14 +44,8 @@ async function handler(args) {
64
44
  uiLogger.log('');
65
45
  uiLogger.log(commands.project.dev.logs.projectAccountFlagExplanation(targetProjectAccountId));
66
46
  }
67
- // Using the legacy --account flag
68
47
  }
69
- else if (userProvidedAccount && derivedAccountId) {
70
- targetProjectAccountId = derivedAccountId;
71
- }
72
- // Determine profile name: from flag or prompt
73
- if (!targetProjectAccountId &&
74
- !isLegacyProject(projectConfig.platformVersion)) {
48
+ if (!targetProjectAccountId) {
75
49
  const profileName = await projectProfilePrompt(projectDir, projectConfig, profileOption);
76
50
  if (profileName) {
77
51
  try {
@@ -88,36 +62,23 @@ async function handler(args) {
88
62
  }
89
63
  }
90
64
  if (!targetProjectAccountId) {
91
- // The user is not using profile or account flags, so we can use the derived accountId
92
65
  targetProjectAccountId = derivedAccountId;
93
- if (useV2Projects) {
94
- uiLogger.log('');
95
- uiLogger.log(commands.project.dev.logs.defaultProjectAccountExplanation(targetProjectAccountId));
96
- }
66
+ uiLogger.log('');
67
+ uiLogger.log(commands.project.dev.logs.defaultProjectAccountExplanation(targetProjectAccountId));
97
68
  }
98
69
  addUsageMetadata({ accountId: targetProjectAccountId ?? undefined });
99
70
  try {
100
- if (!isLegacyProject(projectConfig.platformVersion)) {
101
- const targetTestingAccountId = testingAccount
102
- ? getConfigAccountIfExists(testingAccount)?.accountId
103
- : undefined;
104
- await unifiedProjectDevFlow({
105
- args,
106
- targetProjectAccountId,
107
- providedTargetTestingAccountId: targetTestingAccountId,
108
- projectConfig,
109
- projectDir,
110
- profileConfig: profile,
111
- });
112
- }
113
- else {
114
- await deprecatedProjectDevFlow({
115
- args,
116
- accountId: targetProjectAccountId,
117
- projectConfig,
118
- projectDir,
119
- });
120
- }
71
+ const targetTestingAccountId = testingAccount
72
+ ? getConfigAccountIfExists(testingAccount)?.accountId
73
+ : undefined;
74
+ await unifiedProjectDevFlow({
75
+ args,
76
+ targetProjectAccountId,
77
+ providedTargetTestingAccountId: targetTestingAccountId,
78
+ projectConfig,
79
+ projectDir,
80
+ profileConfig: profile,
81
+ });
121
82
  }
122
83
  catch (e) {
123
84
  if (isPromptExitError(e)) {
@@ -144,19 +105,12 @@ function projectDevBuilder(yargs) {
144
105
  description: commands.project.dev.options.projectAccount,
145
106
  implies: ['testingAccount'],
146
107
  });
147
- yargs.option('account', {
148
- alias: 'a',
149
- describe: '',
150
- type: 'string',
151
- description: commands.project.dev.options.account,
152
- });
153
108
  yargs.option('port', {
154
109
  type: 'number',
155
110
  description: commands.project.dev.options.port,
156
111
  default: LOCAL_DEV_DEFAULT_PORT,
157
112
  });
158
113
  yargs.example([['$0 project dev', commands.project.dev.examples.default]]);
159
- yargs.conflicts('profile', 'account');
160
114
  yargs.conflicts('profile', 'testing-account');
161
115
  yargs.conflicts('profile', 'project-account');
162
116
  return yargs;
@@ -6,6 +6,7 @@ import { isTranslationError, translateForLocalDev, } from '@hubspot/project-pars
6
6
  import { getConfigAccountEnvironment, getLinkedOrAllConfigAccounts, getConfigAccountById, getConfigAccountIfExists, } from '@hubspot/local-dev-lib/config';
7
7
  import { logError } from '../../../lib/errorHandlers/index.js';
8
8
  import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
9
+ import { warnAboutSkippedHsMetaFiles } from '../../../lib/projects/ui.js';
9
10
  import { ensureProjectExists } from '../../../lib/projects/ensureProjectExists.js';
10
11
  import { createInitialBuildForNewProject, createNewProjectForLocalDev, compareLocalProjectToDeployed, checkAndInstallDependencies, } from '../../../lib/projects/localDev/helpers/project.js';
11
12
  import { useExistingDevTestAccount, createDeveloperTestAccountForLocalDev, selectAccountTypePrompt, createSandboxForLocalDev, } from '../../../lib/projects/localDev/helpers/account.js';
@@ -31,7 +32,7 @@ export async function unifiedProjectDevFlow({ args, targetProjectAccountId, prov
31
32
  let projectProfileData;
32
33
  // Get IR
33
34
  try {
34
- const intermediateRepresentation = await translateForLocalDev({
35
+ const { intermediateRepresentation, skippedHsMetaFiles } = await translateForLocalDev({
35
36
  projectSourceDir: path.join(projectDir, projectConfig.srcDir),
36
37
  platformVersion: projectConfig.platformVersion,
37
38
  accountId: targetProjectAccountId,
@@ -39,6 +40,7 @@ export async function unifiedProjectDevFlow({ args, targetProjectAccountId, prov
39
40
  projectNodes = intermediateRepresentation.intermediateNodesIndexedByUid;
40
41
  projectProfileData = intermediateRepresentation.profileData;
41
42
  uiLogger.debug(util.inspect(projectNodes, false, null, true));
43
+ await warnAboutSkippedHsMetaFiles(skippedHsMetaFiles, true, false);
42
44
  }
43
45
  catch (e) {
44
46
  if (isTranslationError(e)) {
@@ -1,4 +1,5 @@
1
1
  import { AccountArgs, CommonArgs, ConfigArgs, EnvironmentArgs, JSONOutputArgs, YargsCommandModule } from '../../types/Yargs.js';
2
- type ProjectInfoArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs;
2
+ import { ProjectInfoJsonOutput } from '../../lib/jsonOutput.js';
3
+ export type ProjectInfoArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs<ProjectInfoJsonOutput>;
3
4
  declare const projectInfoCommand: YargsCommandModule<unknown, ProjectInfoArgs>;
4
5
  export default projectInfoCommand;
@@ -8,11 +8,12 @@ import { commands } from '../../lang/en.js';
8
8
  import { getProjectConfig } from '../../lib/projects/config.js';
9
9
  import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
10
10
  import { getProjectInfo, logProjectInfo, } from '../../lib/projects/projectInfo.js';
11
+ import { ProjectInfoSchema, } from '../../lib/jsonOutput.js';
11
12
  const command = 'info';
12
13
  const describe = commands.project.info.describe;
13
14
  const verboseDescribe = commands.project.info.verboseDescribe;
14
15
  async function handler(args) {
15
- const { derivedAccountId, formatOutputAsJson, exit } = args;
16
+ const { derivedAccountId, formatOutputAsJson, exit, addJsonOutput } = args;
16
17
  const { projectConfig } = await getProjectConfig();
17
18
  if (!projectConfig) {
18
19
  uiLogger.error(commands.project.info.errors.noProjectConfig);
@@ -39,11 +40,10 @@ async function handler(args) {
39
40
  return exit(EXIT_CODES.ERROR);
40
41
  }
41
42
  const projectInfo = await getProjectInfo(project, projectConfig.platformVersion, derivedAccountId);
42
- if (formatOutputAsJson) {
43
- uiLogger.json(projectInfo);
44
- return;
43
+ addJsonOutput(projectInfo);
44
+ if (!formatOutputAsJson) {
45
+ logProjectInfo(projectInfo);
45
46
  }
46
- logProjectInfo(projectInfo);
47
47
  }
48
48
  function projectInfoBuilder(yargs) {
49
49
  yargs.example([
@@ -62,7 +62,9 @@ const builder = makeYargsBuilder(projectInfoBuilder, command, verboseDescribe, {
62
62
  const projectInfoCommand = {
63
63
  command,
64
64
  describe,
65
- handler: makeWrappedYargsHandler('project-info', handler),
65
+ handler: makeWrappedYargsHandler('project-info', handler, {
66
+ jsonOutputSchema: ProjectInfoSchema,
67
+ }),
66
68
  builder,
67
69
  };
68
70
  export default projectInfoCommand;
@@ -1,5 +1,6 @@
1
1
  import { AccountArgs, CommonArgs, ConfigArgs, EnvironmentArgs, JSONOutputArgs, YargsCommandModule } from '../../types/Yargs.js';
2
- type ProjectInstallAppArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs & {
2
+ import { InstallAppJsonOutput } from '../../lib/jsonOutput.js';
3
+ export type ProjectInstallAppArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs<InstallAppJsonOutput> & {
3
4
  force: boolean;
4
5
  profile?: string;
5
6
  };
@@ -1,6 +1,7 @@
1
1
  import { getConfigAccountIfExists } from '@hubspot/local-dev-lib/config';
2
2
  import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
3
3
  import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler.js';
4
+ import { InstallAppSchema, } from '../../lib/jsonOutput.js';
4
5
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
5
6
  import { uiLogger } from '../../lib/ui/logger.js';
6
7
  import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
@@ -13,7 +14,7 @@ const command = 'install-app';
13
14
  const describe = commands.project.installApp.describe;
14
15
  const verboseDescribe = commands.project.installApp.verboseDescribe;
15
16
  async function handler(args) {
16
- const { derivedAccountId, formatOutputAsJson, force, profile: profileOption, useEnv: useEnvOption, exit, } = args;
17
+ const { derivedAccountId, formatOutputAsJson, force, profile: profileOption, useEnv: useEnvOption, exit, addJsonOutput, } = args;
17
18
  const { projectConfig, projectDir } = await getProjectConfig();
18
19
  if (!projectConfig || !projectDir) {
19
20
  uiLogger.error(commands.project.installApp.errors.noProjectConfig);
@@ -27,7 +28,7 @@ async function handler(args) {
27
28
  if (resolvedProjectAccount === null) {
28
29
  return exit(EXIT_CODES.ERROR);
29
30
  }
30
- const appNode = await loadInstallableAppNode(projectConfig, projectDir, resolvedProjectAccount.accountId);
31
+ const appNode = await loadInstallableAppNode(projectConfig, projectDir, resolvedProjectAccount.accountId, force);
31
32
  if (!appNode) {
32
33
  return exit(EXIT_CODES.ERROR);
33
34
  }
@@ -60,18 +61,16 @@ async function handler(args) {
60
61
  const needsReinstall = !isInstalledWithScopeGroups && previouslyAuthorizedScopeGroups.length > 0;
61
62
  const installationState = getAppInstallationState(isInstalledWithScopeGroups, previouslyAuthorizedScopeGroups);
62
63
  if (isInstalledWithScopeGroups) {
63
- if (formatOutputAsJson) {
64
- uiLogger.json({
65
- appId,
66
- appUid: appNode.uid,
67
- accountId: installAccountId,
68
- projectId,
69
- installationState,
70
- installed: true,
71
- reinstalled: false,
72
- });
73
- }
74
- else {
64
+ addJsonOutput({
65
+ appId,
66
+ appUid: appNode.uid,
67
+ accountId: installAccountId,
68
+ projectId,
69
+ installationState,
70
+ installed: true,
71
+ reinstalled: false,
72
+ });
73
+ if (!formatOutputAsJson) {
75
74
  uiLogger.success(commands.project.installApp.alreadyInstalled(appNode.config.name, installAccountId));
76
75
  }
77
76
  return exit(EXIT_CODES.SUCCESS);
@@ -117,18 +116,16 @@ async function handler(args) {
117
116
  if (!installed) {
118
117
  return exit(EXIT_CODES.ERROR);
119
118
  }
120
- if (formatOutputAsJson) {
121
- uiLogger.json({
122
- appId,
123
- appUid: appNode.uid,
124
- accountId: installAccountId,
125
- projectId,
126
- installationState: APP_INSTALLATION_STATES.INSTALLED,
127
- installed: true,
128
- reinstalled: needsReinstall,
129
- });
130
- }
131
- else {
119
+ addJsonOutput({
120
+ appId,
121
+ appUid: appNode.uid,
122
+ accountId: installAccountId,
123
+ projectId,
124
+ installationState: APP_INSTALLATION_STATES.INSTALLED,
125
+ installed: true,
126
+ reinstalled: needsReinstall,
127
+ });
128
+ if (!formatOutputAsJson) {
132
129
  uiLogger.success(commands.project.installApp.success(appNode.config.name, installAccountId));
133
130
  }
134
131
  return exit(EXIT_CODES.SUCCESS);
@@ -175,7 +172,9 @@ const builder = makeYargsBuilder(projectInstallAppBuilder, command, verboseDescr
175
172
  const projectInstallAppCommand = {
176
173
  command,
177
174
  describe,
178
- handler: makeWrappedYargsHandler('project-install-app', handler),
175
+ handler: makeWrappedYargsHandler('project-install-app', handler, {
176
+ jsonOutputSchema: InstallAppSchema,
177
+ }),
179
178
  builder,
180
179
  };
181
180
  export default projectInstallAppCommand;
@@ -57,7 +57,7 @@ const builder = makeYargsBuilder(projectListBuilder, command, describe, {
57
57
  const projectListCommand = {
58
58
  command,
59
59
  describe,
60
- handler: makeWrappedYargsHandler('projects-list', handler),
60
+ handler: makeWrappedYargsHandler('project-list', handler),
61
61
  builder,
62
62
  };
63
63
  export default projectListCommand;
@@ -1,5 +1,5 @@
1
1
  import { CommonArgs, ConfigArgs, AccountArgs, EnvironmentArgs, YargsCommandModule } from '../../types/Yargs.js';
2
- type ProjectListBuildsArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & {
2
+ export type ProjectListBuildsArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & {
3
3
  project?: string;
4
4
  limit?: number;
5
5
  };
@@ -17,12 +17,6 @@ const describe = commands.project.listBuilds.describe;
17
17
  async function fetchAndDisplayBuilds(accountId, project, options) {
18
18
  const { data: { results, paging }, } = await fetchProjectBuilds(accountId, project.name, options);
19
19
  const currentDeploy = project.deployedBuildId;
20
- if (options && options.after) {
21
- uiLogger.log(commands.project.listBuilds.showingNextBuilds(results.length, project.name));
22
- }
23
- else {
24
- uiLogger.log(commands.project.listBuilds.showingRecentBuilds(results.length, project.name, uiLink(commands.project.listBuilds.viewAllBuildsLink, getProjectDetailUrl(project.name, accountId))));
25
- }
26
20
  if (results.length === 0) {
27
21
  uiLogger.log(commands.project.listBuilds.errors.noBuilds);
28
22
  }
@@ -46,6 +40,14 @@ async function fetchAndDisplayBuilds(accountId, project, options) {
46
40
  });
47
41
  renderTable(['Build ID', 'Status', 'Completed', 'Duration', 'Details'], builds);
48
42
  }
43
+ if (options && options.after) {
44
+ if (results.length > 0) {
45
+ uiLogger.log(commands.project.listBuilds.showingNextBuilds(results.length, project.name));
46
+ }
47
+ }
48
+ else {
49
+ uiLogger.log(commands.project.listBuilds.showingRecentBuilds(results.length, project.name, uiLink(commands.project.listBuilds.viewAllBuildsLink, getProjectDetailUrl(project.name, accountId))));
50
+ }
49
51
  if (paging && paging.next) {
50
52
  await promptUser({
51
53
  name: 'more',
@@ -1,5 +1,4 @@
1
- import { getConfigAccountEnvironment } from '@hubspot/local-dev-lib/config';
2
- import { getHubSpotWebsiteOrigin } from '@hubspot/local-dev-lib/urls';
1
+ import { getHubSpotWebsiteOriginByAccountId } from '@hubspot/local-dev-lib/urls';
3
2
  import { logError } from '../../lib/errorHandlers/index.js';
4
3
  import { uiLine } from '../../lib/ui/index.js';
5
4
  import { projectLogsPrompt } from '../../lib/prompts/projectsLogsPrompt.js';
@@ -11,8 +10,7 @@ import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler
11
10
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
12
11
  import { renderTable } from '../../ui/render.js';
13
12
  function getPrivateAppsUrl(accountId) {
14
- const baseUrl = getHubSpotWebsiteOrigin(getConfigAccountEnvironment(accountId));
15
- return `${baseUrl}/private-apps/${accountId}`;
13
+ return `${getHubSpotWebsiteOriginByAccountId(accountId)}/private-apps/${accountId}`;
16
14
  }
17
15
  function logPreamble() {
18
16
  if (ProjectLogsManager.isPublicFunction) {
@@ -1,7 +1,8 @@
1
1
  import { YargsCommandModule, CommonArgs } from '../../../types/Yargs.js';
2
- type ProjectProfileAddArgs = CommonArgs & {
2
+ export type ProjectProfileAddArgs = CommonArgs & {
3
3
  name?: string;
4
4
  targetAccount?: number;
5
+ copyFrom?: string;
5
6
  };
6
7
  declare const projectProfileAddCommand: YargsCommandModule<unknown, ProjectProfileAddArgs>;
7
8
  export default projectProfileAddCommand;
@@ -157,7 +157,20 @@ async function handler(args) {
157
157
  accountId: targetAccountId,
158
158
  variables: {},
159
159
  };
160
- const profileToCopyVariablesFrom = await selectProfileToCopyVariablesFrom(existingProfiles);
160
+ let profileToCopyVariablesFrom;
161
+ if (args.copyFrom) {
162
+ if (existingProfiles.includes(args.copyFrom)) {
163
+ profileToCopyVariablesFrom = args.copyFrom;
164
+ }
165
+ else {
166
+ uiLogger.error(commands.project.profile.add.errors.copyFromProfileNotFound(args.copyFrom));
167
+ return exit(EXIT_CODES.ERROR);
168
+ }
169
+ }
170
+ else {
171
+ profileToCopyVariablesFrom =
172
+ await selectProfileToCopyVariablesFrom(existingProfiles);
173
+ }
161
174
  if (profileToCopyVariablesFrom) {
162
175
  try {
163
176
  const profileToCopyFileContent = loadHsProfileFile(projectSourceDir, profileToCopyVariablesFrom);
@@ -190,8 +203,16 @@ function projectProfileAddBuilder(yargs) {
190
203
  describe: commands.project.profile.add.options.targetAccount,
191
204
  type: 'number',
192
205
  });
206
+ yargs.option('copy-from', {
207
+ describe: commands.project.profile.add.options.copyFrom,
208
+ type: 'string',
209
+ });
193
210
  yargs.example([
194
211
  ['$0 project profile add qa', commands.project.profile.add.example],
212
+ [
213
+ '$0 project profile add qa --target-account 123 --copy-from staging',
214
+ commands.project.profile.add.exampleCopyFrom,
215
+ ],
195
216
  ]);
196
217
  return yargs;
197
218
  }
@@ -1,5 +1,5 @@
1
1
  import { YargsCommandModule, CommonArgs } from '../../../types/Yargs.js';
2
- type ProjectProfileDeleteArgs = CommonArgs & {
2
+ export type ProjectProfileDeleteArgs = CommonArgs & {
3
3
  name?: string;
4
4
  };
5
5
  declare const projectProfileDeleteCommand: YargsCommandModule<unknown, ProjectProfileDeleteArgs>;
@@ -1,5 +1,6 @@
1
1
  import { CommonArgs, ConfigArgs, AccountArgs, EnvironmentArgs, JSONOutputArgs, YargsCommandModule } from '../../../types/Yargs.js';
2
- export type ProjectReleaseCreateArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs & {
2
+ import { ReleaseJsonOutput } from '../../../lib/jsonOutput.js';
3
+ export type ProjectReleaseCreateArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs<ReleaseJsonOutput> & {
3
4
  build?: number;
4
5
  force: boolean;
5
6
  };
@@ -1,6 +1,8 @@
1
- import { fetchProject, getBuildStatus, } from '@hubspot/local-dev-lib/api/projects';
2
- import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
1
+ import { handleProjectUpload } from '../../../lib/projects/upload.js';
2
+ import { pollProjectBuildAndDeploy } from '../../../lib/projects/pollProjectBuildAndDeploy.js';
3
+ import { resolveBuildId, validateBuildForRelease, executeRelease, } from '../../../lib/projects/release.js';
3
4
  import { logError, ApiErrorContext } from '../../../lib/errorHandlers/index.js';
5
+ import { isPromptExitError } from '../../../lib/errors/PromptExitError.js';
4
6
  import { getProjectConfig, validateProjectConfig, } from '../../../lib/projects/config.js';
5
7
  import { confirmPrompt } from '../../../lib/prompts/promptUtils.js';
6
8
  import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
@@ -8,64 +10,23 @@ import { uiLogger } from '../../../lib/ui/logger.js';
8
10
  import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
9
11
  import { commands } from '../../../lang/en.js';
10
12
  import { makeWrappedYargsHandler } from '../../../lib/yargs/makeWrappedYargsHandler.js';
11
- import { createRelease } from '../../../api/releases.js';
13
+ import { ReleaseSchema, mapReleaseToJsonOutput, } from '../../../lib/jsonOutput.js';
12
14
  const command = 'create';
13
15
  // const describe = commands.project.release.create.describe;
14
16
  const describe = undefined;
15
17
  // const verboseDescribe = commands.project.release.create.verboseDescribe;
16
18
  const verboseDescribe = undefined;
17
- async function resolveBuildId(accountId, projectName, buildOption) {
18
- const { data: { deployedBuildId }, } = await fetchProject(accountId, projectName);
19
- if (buildOption) {
20
- return buildOption;
21
- }
22
- if (!deployedBuildId) {
23
- throw new Error(commands.project.release.create.errors.noDeployedBuild);
24
- }
25
- return deployedBuildId;
26
- }
27
- async function validateBuild(accountId, projectName, buildId) {
28
- try {
29
- await getBuildStatus(accountId, projectName, buildId);
30
- }
31
- catch (e) {
32
- if (isHubSpotHttpError(e) && e.status === 404) {
33
- uiLogger.error(commands.project.release.create.errors.buildNotFound(buildId, projectName));
34
- }
35
- else {
36
- logError(e, new ApiErrorContext({
37
- accountId,
38
- request: 'project release create',
39
- }));
40
- }
41
- throw e;
42
- }
43
- }
44
- async function executeRelease(accountId, projectName, buildId, formatOutputAsJson) {
45
- try {
46
- const { data: release } = await createRelease(accountId, projectName, buildId);
47
- if (formatOutputAsJson) {
48
- uiLogger.json(release);
49
- }
50
- else {
51
- uiLogger.success(commands.project.release.create.success(release.releaseTag, release.buildId));
52
- }
53
- }
54
- catch (e) {
55
- if (isHubSpotHttpError(e) && e.status === 422) {
56
- uiLogger.error(commands.project.release.create.errors.buildNotDeployed(buildId));
57
- }
58
- else {
59
- logError(e, new ApiErrorContext({
60
- accountId,
61
- request: 'project release create',
62
- }));
63
- }
64
- throw e;
19
+ function logUploadError(error, accountId) {
20
+ if (!error) {
21
+ return;
65
22
  }
23
+ logError(error, new ApiErrorContext({
24
+ accountId,
25
+ request: 'project release create',
26
+ }));
66
27
  }
67
28
  async function handler(args) {
68
- const { exit, derivedAccountId, build: buildOption, json: formatOutputAsJson, force, } = args;
29
+ const { exit, derivedAccountId, build: buildOption, json: formatOutputAsJson, force, addJsonOutput, } = args;
69
30
  const { projectConfig, projectDir } = await getProjectConfig();
70
31
  try {
71
32
  validateProjectConfig(projectConfig, projectDir);
@@ -74,34 +35,66 @@ async function handler(args) {
74
35
  logError(error);
75
36
  return exit(EXIT_CODES.ERROR);
76
37
  }
38
+ if (!projectConfig || !projectDir) {
39
+ return exit(EXIT_CODES.ERROR);
40
+ }
77
41
  const projectName = projectConfig.name;
78
42
  let buildId;
79
43
  try {
80
- buildId = await resolveBuildId(derivedAccountId, projectName, buildOption);
44
+ buildId = await resolveBuildId(derivedAccountId, projectName, buildOption, force);
81
45
  }
82
46
  catch (e) {
83
- if (isHubSpotHttpError(e) && e.status === 404) {
84
- uiLogger.error(commands.project.release.create.errors.projectNotFound(derivedAccountId, projectName));
85
- }
86
- else if (!(e instanceof Error) || !e.message) {
87
- logError(e, new ApiErrorContext({
88
- accountId: derivedAccountId,
89
- request: 'project release create',
90
- }));
91
- }
92
- else {
93
- uiLogger.error(e.message);
47
+ if (isPromptExitError(e)) {
48
+ return exit(e.exitCode);
94
49
  }
50
+ logError(e, new ApiErrorContext({
51
+ accountId: derivedAccountId,
52
+ request: 'project release create',
53
+ }));
54
+ return exit(EXIT_CODES.ERROR);
55
+ }
56
+ if (buildId === null) {
95
57
  return exit(EXIT_CODES.ERROR);
96
58
  }
97
- if (buildOption) {
59
+ if (!buildId && !force) {
60
+ let shouldUpload;
98
61
  try {
99
- await validateBuild(derivedAccountId, projectName, buildId);
62
+ shouldUpload = await confirmPrompt(commands.project.release.create.uploadPrompt(projectName));
63
+ }
64
+ catch (e) {
65
+ if (isPromptExitError(e)) {
66
+ return exit(e.exitCode);
67
+ }
68
+ throw e;
69
+ }
70
+ if (!shouldUpload) {
71
+ return exit(EXIT_CODES.SUCCESS);
72
+ }
73
+ }
74
+ if (!buildId) {
75
+ const { result: pollResult, uploadError, projectNotFound, } = await handleProjectUpload({
76
+ accountId: derivedAccountId,
77
+ projectConfig,
78
+ projectDir,
79
+ sendIR: true,
80
+ callbackFunc: (...args) => pollProjectBuildAndDeploy(...args, { skipDeploy: true }),
81
+ });
82
+ if (projectNotFound || !pollResult || !pollResult.succeeded) {
83
+ logUploadError(uploadError, derivedAccountId);
84
+ return exit(EXIT_CODES.ERROR);
100
85
  }
101
- catch {
86
+ buildId = pollResult.buildId;
87
+ }
88
+ try {
89
+ const supportsReleases = await validateBuildForRelease(derivedAccountId, projectName, buildId);
90
+ if (!supportsReleases) {
91
+ uiLogger.error(commands.project.release.create.errors.incompatibleBuildVersion);
102
92
  return exit(EXIT_CODES.ERROR);
103
93
  }
104
94
  }
95
+ catch {
96
+ return exit(EXIT_CODES.ERROR);
97
+ }
105
98
  if (!formatOutputAsJson && !force) {
106
99
  const confirmed = await confirmPrompt(commands.project.release.create.confirmPrompt(projectName, buildId));
107
100
  if (!confirmed) {
@@ -110,7 +103,11 @@ async function handler(args) {
110
103
  }
111
104
  }
112
105
  try {
113
- await executeRelease(derivedAccountId, projectName, buildId, !!formatOutputAsJson);
106
+ const release = await executeRelease(derivedAccountId, projectName, buildId);
107
+ addJsonOutput(mapReleaseToJsonOutput(release));
108
+ if (!formatOutputAsJson) {
109
+ uiLogger.success(commands.project.release.create.success(release.releaseTag, release.buildId));
110
+ }
114
111
  }
115
112
  catch {
116
113
  return exit(EXIT_CODES.ERROR);
@@ -154,6 +151,8 @@ const projectReleaseCreateCommand = {
154
151
  command,
155
152
  describe,
156
153
  builder,
157
- handler: makeWrappedYargsHandler('project-release-create', handler),
154
+ handler: makeWrappedYargsHandler('project-release-create', handler, {
155
+ jsonOutputSchema: ReleaseSchema,
156
+ }),
158
157
  };
159
158
  export default projectReleaseCreateCommand;
@@ -1,5 +1,6 @@
1
1
  import { CommonArgs, ConfigArgs, AccountArgs, EnvironmentArgs, JSONOutputArgs, YargsCommandModule } from '../../../types/Yargs.js';
2
- export type ProjectReleaseInfoArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs & {
2
+ import { ReleaseJsonOutput } from '../../../lib/jsonOutput.js';
3
+ export type ProjectReleaseInfoArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs<ReleaseJsonOutput> & {
3
4
  tag?: string;
4
5
  };
5
6
  declare const projectReleaseInfoCommand: YargsCommandModule<unknown, ProjectReleaseInfoArgs>;