@hubspot/cli 8.6.0 → 8.7.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 (149) hide show
  1. package/api/releases.d.ts +36 -0
  2. package/api/releases.js +41 -0
  3. package/bin/cli.js +3 -3
  4. package/commands/account/auth.js +2 -2
  5. package/commands/account/clean.js +2 -2
  6. package/commands/account/createOverride.js +2 -2
  7. package/commands/account/info.js +2 -2
  8. package/commands/account/link.js +2 -2
  9. package/commands/account/list.js +2 -2
  10. package/commands/account/remove.js +2 -2
  11. package/commands/account/removeOverride.js +2 -2
  12. package/commands/account/rename.js +2 -2
  13. package/commands/account/unlink.js +2 -2
  14. package/commands/account/use.js +2 -2
  15. package/commands/api.js +2 -2
  16. package/commands/app/migrate.js +2 -2
  17. package/commands/app/secret/add.js +2 -2
  18. package/commands/app/secret/delete.js +2 -2
  19. package/commands/app/secret/list.js +2 -2
  20. package/commands/app/secret/update.js +2 -2
  21. package/commands/auth.js +2 -2
  22. package/commands/cms/app/create.js +2 -2
  23. package/commands/cms/convertFields.js +2 -2
  24. package/commands/cms/delete.js +2 -2
  25. package/commands/cms/fetch.js +2 -2
  26. package/commands/cms/function/create.js +2 -2
  27. package/commands/cms/function/deploy.js +2 -2
  28. package/commands/cms/function/list.js +2 -2
  29. package/commands/cms/function/logs.js +2 -2
  30. package/commands/cms/function/server.js +2 -2
  31. package/commands/cms/getReactModule.js +2 -2
  32. package/commands/cms/lighthouseScore.js +2 -2
  33. package/commands/cms/lint.js +2 -2
  34. package/commands/cms/list.js +2 -2
  35. package/commands/cms/module/create.js +8 -2
  36. package/commands/cms/module/marketplace-validate.js +2 -2
  37. package/commands/cms/mv.js +2 -2
  38. package/commands/cms/template/create.js +2 -2
  39. package/commands/cms/theme/create.js +2 -2
  40. package/commands/cms/theme/generate-selectors.js +2 -2
  41. package/commands/cms/theme/marketplace-validate.js +2 -2
  42. package/commands/cms/theme/preview.js +2 -2
  43. package/commands/cms/upload.js +2 -2
  44. package/commands/cms/watch.js +2 -2
  45. package/commands/cms/webpack/create.js +2 -2
  46. package/commands/completion.js +2 -2
  47. package/commands/config/migrate.js +2 -2
  48. package/commands/config/set.js +2 -2
  49. package/commands/customObject/create.js +2 -2
  50. package/commands/customObject/createSchema.js +2 -2
  51. package/commands/customObject/deleteSchema.js +2 -2
  52. package/commands/customObject/fetchAllSchemas.js +2 -2
  53. package/commands/customObject/fetchSchema.js +2 -2
  54. package/commands/customObject/listSchemas.js +2 -2
  55. package/commands/customObject/updateSchema.js +2 -2
  56. package/commands/doctor.js +2 -2
  57. package/commands/feedback.js +2 -2
  58. package/commands/filemanager/fetch.js +2 -2
  59. package/commands/filemanager/upload.js +2 -2
  60. package/commands/getStarted.js +2 -2
  61. package/commands/hubdb/clear.js +2 -2
  62. package/commands/hubdb/create.js +2 -2
  63. package/commands/hubdb/delete.js +2 -2
  64. package/commands/hubdb/fetch.js +2 -2
  65. package/commands/hubdb/list.js +2 -2
  66. package/commands/init.js +2 -2
  67. package/commands/mcp/setup.js +2 -2
  68. package/commands/mcp/start.js +2 -2
  69. package/commands/open.js +2 -2
  70. package/commands/project/add.js +2 -2
  71. package/commands/project/appInstallStatus.d.ts +2 -2
  72. package/commands/project/appInstallStatus.js +3 -2
  73. package/commands/project/create.js +2 -2
  74. package/commands/project/delete.js +2 -2
  75. package/commands/project/deploy.js +2 -2
  76. package/commands/project/dev/index.js +2 -2
  77. package/commands/project/download.js +2 -2
  78. package/commands/project/info.d.ts +2 -2
  79. package/commands/project/info.js +3 -2
  80. package/commands/project/installDeps.js +2 -2
  81. package/commands/project/lint.js +7 -5
  82. package/commands/project/list.d.ts +2 -2
  83. package/commands/project/list.js +3 -2
  84. package/commands/project/listBuilds.js +2 -2
  85. package/commands/project/logs.js +2 -2
  86. package/commands/project/migrate.js +2 -2
  87. package/commands/project/open.js +2 -2
  88. package/commands/project/profile/add.js +2 -2
  89. package/commands/project/profile/delete.js +2 -2
  90. package/commands/project/release/create.d.ts +7 -0
  91. package/commands/project/release/create.js +159 -0
  92. package/commands/project/release/info.d.ts +6 -0
  93. package/commands/project/release/info.js +147 -0
  94. package/commands/project/release/list.d.ts +6 -0
  95. package/commands/project/release/list.js +111 -0
  96. package/commands/project/release.d.ts +3 -0
  97. package/commands/project/release.js +20 -0
  98. package/commands/project/updateDeps.js +2 -2
  99. package/commands/project/upload.d.ts +3 -0
  100. package/commands/project/upload.js +77 -9
  101. package/commands/project/validate.js +2 -2
  102. package/commands/project/watch.js +2 -2
  103. package/commands/project.js +2 -0
  104. package/commands/sandbox/create.js +2 -2
  105. package/commands/sandbox/delete.js +2 -2
  106. package/commands/secret/addSecret.js +2 -2
  107. package/commands/secret/deleteSecret.js +2 -2
  108. package/commands/secret/listSecret.js +2 -2
  109. package/commands/secret/updateSecret.js +2 -2
  110. package/commands/testAccount/create.js +2 -2
  111. package/commands/testAccount/createConfig.js +2 -2
  112. package/commands/testAccount/delete.js +2 -2
  113. package/commands/testAccount/importData.js +2 -2
  114. package/commands/upgrade.js +2 -2
  115. package/lang/en.d.ts +92 -0
  116. package/lang/en.js +92 -0
  117. package/lib/api/usageTracking.d.ts +29 -0
  118. package/lib/api/usageTracking.js +28 -0
  119. package/lib/commonOpts.js +0 -1
  120. package/lib/constants.d.ts +1 -0
  121. package/lib/constants.js +1 -0
  122. package/lib/projects/localDev/helpers/project.js +1 -1
  123. package/lib/projects/npmAuditOnUpload.d.ts +10 -0
  124. package/lib/projects/npmAuditOnUpload.js +73 -0
  125. package/lib/projects/pollProjectBuildAndDeploy.d.ts +5 -1
  126. package/lib/projects/pollProjectBuildAndDeploy.js +3 -2
  127. package/lib/projects/preview.d.ts +7 -0
  128. package/lib/projects/preview.js +48 -0
  129. package/lib/projects/uieLinting.d.ts +4 -0
  130. package/lib/projects/uieLinting.js +36 -1
  131. package/lib/projects/upload.d.ts +3 -1
  132. package/lib/projects/upload.js +26 -6
  133. package/lib/projects/validateLintConfigOnUpload.d.ts +9 -0
  134. package/lib/projects/validateLintConfigOnUpload.js +45 -0
  135. package/lib/projects/workspaces.d.ts +11 -1
  136. package/lib/projects/workspaces.js +27 -12
  137. package/lib/usageTracking.d.ts +7 -17
  138. package/lib/usageTracking.js +43 -29
  139. package/lib/yargs/makeWrappedYargsHandler.d.ts +3 -0
  140. package/lib/yargs/{makeYargsHandlerWithUsageTracking.js → makeWrappedYargsHandler.js} +29 -3
  141. package/mcp-server/tools/cms/HsCreateFunctionTool.js +2 -2
  142. package/mcp-server/tools/cms/HsCreateModuleTool.js +4 -5
  143. package/mcp-server/tools/cms/HsCreateTemplateTool.js +2 -2
  144. package/mcp-server/tools/cms/HsFunctionLogsTool.js +2 -3
  145. package/mcp-server/tools/cms/HsListFunctionsTool.js +2 -3
  146. package/mcp-server/tools/cms/HsListTool.js +2 -2
  147. package/mcp-server/utils/toolUsageTracking.js +10 -6
  148. package/package.json +4 -4
  149. package/lib/yargs/makeYargsHandlerWithUsageTracking.d.ts +0 -3
@@ -0,0 +1,159 @@
1
+ import { fetchProject, getBuildStatus, } from '@hubspot/local-dev-lib/api/projects';
2
+ import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
3
+ import { logError, ApiErrorContext } from '../../../lib/errorHandlers/index.js';
4
+ import { getProjectConfig, validateProjectConfig, } from '../../../lib/projects/config.js';
5
+ import { confirmPrompt } from '../../../lib/prompts/promptUtils.js';
6
+ import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
7
+ import { uiLogger } from '../../../lib/ui/logger.js';
8
+ import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
9
+ import { commands } from '../../../lang/en.js';
10
+ import { makeWrappedYargsHandler } from '../../../lib/yargs/makeWrappedYargsHandler.js';
11
+ import { createRelease } from '../../../api/releases.js';
12
+ const command = 'create';
13
+ // const describe = commands.project.release.create.describe;
14
+ const describe = undefined;
15
+ // const verboseDescribe = commands.project.release.create.verboseDescribe;
16
+ 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;
65
+ }
66
+ }
67
+ async function handler(args) {
68
+ const { exit, derivedAccountId, build: buildOption, json: formatOutputAsJson, force, } = args;
69
+ const { projectConfig, projectDir } = await getProjectConfig();
70
+ try {
71
+ validateProjectConfig(projectConfig, projectDir);
72
+ }
73
+ catch (error) {
74
+ logError(error);
75
+ return exit(EXIT_CODES.ERROR);
76
+ }
77
+ const projectName = projectConfig.name;
78
+ let buildId;
79
+ try {
80
+ buildId = await resolveBuildId(derivedAccountId, projectName, buildOption);
81
+ }
82
+ 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);
94
+ }
95
+ return exit(EXIT_CODES.ERROR);
96
+ }
97
+ if (buildOption) {
98
+ try {
99
+ await validateBuild(derivedAccountId, projectName, buildId);
100
+ }
101
+ catch {
102
+ return exit(EXIT_CODES.ERROR);
103
+ }
104
+ }
105
+ if (!formatOutputAsJson && !force) {
106
+ const confirmed = await confirmPrompt(commands.project.release.create.confirmPrompt(projectName, buildId));
107
+ if (!confirmed) {
108
+ uiLogger.log(commands.project.release.create.cancelled);
109
+ return exit(EXIT_CODES.SUCCESS);
110
+ }
111
+ }
112
+ try {
113
+ await executeRelease(derivedAccountId, projectName, buildId, !!formatOutputAsJson);
114
+ }
115
+ catch {
116
+ return exit(EXIT_CODES.ERROR);
117
+ }
118
+ return exit(EXIT_CODES.SUCCESS);
119
+ }
120
+ function projectReleaseCreateBuilder(yargs) {
121
+ yargs.options({
122
+ build: {
123
+ alias: ['build-id'],
124
+ describe: commands.project.release.create.options.build,
125
+ type: 'number',
126
+ },
127
+ force: {
128
+ alias: ['f'],
129
+ describe: commands.project.release.create.options.force,
130
+ default: false,
131
+ type: 'boolean',
132
+ },
133
+ });
134
+ yargs.example([
135
+ [
136
+ '$0 project release create',
137
+ commands.project.release.create.examples.default,
138
+ ],
139
+ [
140
+ '$0 project release create --build=5',
141
+ commands.project.release.create.examples.withBuild,
142
+ ],
143
+ ]);
144
+ return yargs;
145
+ }
146
+ const builder = makeYargsBuilder(projectReleaseCreateBuilder, command, verboseDescribe, {
147
+ useGlobalOptions: true,
148
+ useConfigOptions: true,
149
+ useAccountOptions: true,
150
+ useEnvironmentOptions: true,
151
+ useJSONOutputOptions: true,
152
+ });
153
+ const projectReleaseCreateCommand = {
154
+ command,
155
+ describe,
156
+ builder,
157
+ handler: makeWrappedYargsHandler('project-release-create', handler),
158
+ };
159
+ export default projectReleaseCreateCommand;
@@ -0,0 +1,6 @@
1
+ import { CommonArgs, ConfigArgs, AccountArgs, EnvironmentArgs, JSONOutputArgs, YargsCommandModule } from '../../../types/Yargs.js';
2
+ export type ProjectReleaseInfoArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs & {
3
+ tag?: string;
4
+ };
5
+ declare const projectReleaseInfoCommand: YargsCommandModule<unknown, ProjectReleaseInfoArgs>;
6
+ export default projectReleaseInfoCommand;
@@ -0,0 +1,147 @@
1
+ import { getReleaseInfo, listReleases } from '../../../api/releases.js';
2
+ import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
3
+ import { logError, ApiErrorContext } from '../../../lib/errorHandlers/index.js';
4
+ import { getProjectConfig, validateProjectConfig, } from '../../../lib/projects/config.js';
5
+ import { listPrompt } from '../../../lib/prompts/promptUtils.js';
6
+ import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
7
+ import { uiLogger } from '../../../lib/ui/logger.js';
8
+ import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
9
+ import { commands } from '../../../lang/en.js';
10
+ import { renderTable } from '../../../ui/render.js';
11
+ import { makeWrappedYargsHandler } from '../../../lib/yargs/makeWrappedYargsHandler.js';
12
+ import { isPromptExitError } from '../../../lib/errors/PromptExitError.js';
13
+ import { mapToUserFacingType } from '@hubspot/project-parsing-lib/transform';
14
+ import { AUTO_GENERATED_COMPONENT_TYPES } from '@hubspot/project-parsing-lib/constants';
15
+ const command = 'info';
16
+ // const describe = commands.project.release.info.describe;
17
+ const describe = undefined;
18
+ // const verboseDescribe = commands.project.release.info.verboseDescribe;
19
+ const verboseDescribe = undefined;
20
+ function normalizeTag(rawTag) {
21
+ return rawTag.startsWith('v') ? rawTag : `v${rawTag}`;
22
+ }
23
+ async function selectReleasePrompt(accountId, projectName) {
24
+ const { data: { results, paging }, } = await listReleases(accountId, projectName);
25
+ if (results.length === 0) {
26
+ return null;
27
+ }
28
+ if (paging?.next?.after) {
29
+ uiLogger.info(commands.project.release.info.moreReleasesHint);
30
+ }
31
+ return listPrompt(commands.project.release.info.selectRelease(projectName), {
32
+ choices: results.map(release => ({
33
+ name: `${release.releaseTag} (build #${release.buildId}, ${new Date(release.createdAt).toLocaleString()})`,
34
+ value: release.releaseTag,
35
+ })),
36
+ });
37
+ }
38
+ async function handler(args) {
39
+ const { derivedAccountId, tag: rawTag, json: formatOutputAsJson, exit, } = args;
40
+ const { projectConfig, projectDir } = await getProjectConfig();
41
+ try {
42
+ validateProjectConfig(projectConfig, projectDir);
43
+ }
44
+ catch (error) {
45
+ logError(error);
46
+ return exit(EXIT_CODES.ERROR);
47
+ }
48
+ const projectName = projectConfig.name;
49
+ let tag;
50
+ if (rawTag) {
51
+ tag = normalizeTag(rawTag);
52
+ }
53
+ else {
54
+ try {
55
+ const selected = await selectReleasePrompt(derivedAccountId, projectName);
56
+ if (!selected) {
57
+ uiLogger.error(commands.project.release.info.errors.noReleases);
58
+ return exit(EXIT_CODES.ERROR);
59
+ }
60
+ tag = selected;
61
+ }
62
+ catch (e) {
63
+ if (isPromptExitError(e)) {
64
+ throw e;
65
+ }
66
+ logError(e);
67
+ return exit(EXIT_CODES.ERROR);
68
+ }
69
+ }
70
+ try {
71
+ const { data: release } = await getReleaseInfo(derivedAccountId, projectName, tag);
72
+ if (formatOutputAsJson) {
73
+ uiLogger.json(release);
74
+ }
75
+ else {
76
+ uiLogger.log(commands.project.release.info.releaseDetails(release.releaseTag, projectName));
77
+ renderTable(['Release', 'Build', 'Created'], [
78
+ [
79
+ release.releaseTag,
80
+ `#${release.buildId}`,
81
+ new Date(release.createdAt).toLocaleString(),
82
+ ],
83
+ ]);
84
+ const visibleComponents = (release.components ?? []).filter(component => !AUTO_GENERATED_COMPONENT_TYPES.includes(component.buildType));
85
+ if (visibleComponents.length > 0) {
86
+ uiLogger.log('');
87
+ uiLogger.log(commands.project.release.info.components);
88
+ const componentRows = visibleComponents.map(component => [
89
+ mapToUserFacingType(component.buildType),
90
+ component.buildName ?? '',
91
+ component.rootPath ?? '',
92
+ ]);
93
+ renderTable(['Type', 'Name', 'Path'], componentRows);
94
+ }
95
+ else {
96
+ uiLogger.log('');
97
+ uiLogger.log(commands.project.release.info.noComponents);
98
+ }
99
+ }
100
+ }
101
+ catch (e) {
102
+ if (isHubSpotHttpError(e) && e.status === 404) {
103
+ uiLogger.error(commands.project.release.info.errors.releaseNotFound(tag, projectName));
104
+ }
105
+ else {
106
+ logError(e, new ApiErrorContext({
107
+ accountId: derivedAccountId,
108
+ request: 'project release info',
109
+ }));
110
+ }
111
+ return exit(EXIT_CODES.ERROR);
112
+ }
113
+ return exit(EXIT_CODES.SUCCESS);
114
+ }
115
+ function projectReleaseInfoBuilder(yargs) {
116
+ yargs.options({
117
+ tag: {
118
+ describe: commands.project.release.info.options.tag,
119
+ type: 'string',
120
+ },
121
+ });
122
+ yargs.example([
123
+ [
124
+ '$0 project release info --tag=v1.0.0',
125
+ commands.project.release.info.examples.default,
126
+ ],
127
+ [
128
+ '$0 project release info --tag=v1.0.0 --json',
129
+ commands.project.release.info.examples.json,
130
+ ],
131
+ ]);
132
+ return yargs;
133
+ }
134
+ const builder = makeYargsBuilder(projectReleaseInfoBuilder, command, verboseDescribe, {
135
+ useGlobalOptions: true,
136
+ useConfigOptions: true,
137
+ useAccountOptions: true,
138
+ useEnvironmentOptions: true,
139
+ useJSONOutputOptions: true,
140
+ });
141
+ const projectReleaseInfoCommand = {
142
+ command,
143
+ describe,
144
+ builder,
145
+ handler: makeWrappedYargsHandler('project-release-info', handler),
146
+ };
147
+ export default projectReleaseInfoCommand;
@@ -0,0 +1,6 @@
1
+ import { CommonArgs, ConfigArgs, AccountArgs, EnvironmentArgs, JSONOutputArgs, YargsCommandModule } from '../../../types/Yargs.js';
2
+ export type ProjectReleaseListArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs & {
3
+ limit?: number;
4
+ };
5
+ declare const projectReleaseListCommand: YargsCommandModule<unknown, ProjectReleaseListArgs>;
6
+ export default projectReleaseListCommand;
@@ -0,0 +1,111 @@
1
+ import { listReleases } from '../../../api/releases.js';
2
+ import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
3
+ import { isPromptExitError } from '../../../lib/errors/PromptExitError.js';
4
+ import { logError, ApiErrorContext } from '../../../lib/errorHandlers/index.js';
5
+ import { getProjectConfig, validateProjectConfig, } from '../../../lib/projects/config.js';
6
+ import { promptUser } from '../../../lib/prompts/promptUtils.js';
7
+ import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
8
+ import { uiLogger } from '../../../lib/ui/logger.js';
9
+ import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
10
+ import { commands } from '../../../lang/en.js';
11
+ import { renderTable } from '../../../ui/render.js';
12
+ import { makeWrappedYargsHandler } from '../../../lib/yargs/makeWrappedYargsHandler.js';
13
+ const command = 'list';
14
+ // const describe = commands.project.release.list.describe;
15
+ const describe = undefined;
16
+ // const verboseDescribe = commands.project.release.list.verboseDescribe;
17
+ const verboseDescribe = undefined;
18
+ async function fetchAndDisplayReleases(accountId, projectName, options) {
19
+ const { data: { results, paging }, } = await listReleases(accountId, projectName, options);
20
+ uiLogger.log(commands.project.release.list.showingReleases(results.length, projectName));
21
+ if (results.length === 0) {
22
+ uiLogger.log(commands.project.release.list.noReleases);
23
+ }
24
+ else {
25
+ const rows = results.map(release => [
26
+ release.releaseTag,
27
+ `#${release.buildId}`,
28
+ new Date(release.createdAt).toLocaleString(),
29
+ ]);
30
+ renderTable(['Release', 'Build', 'Created'], rows);
31
+ }
32
+ if (paging?.next?.after) {
33
+ await promptUser({
34
+ name: 'more',
35
+ message: commands.project.release.list.continueOrExitPrompt,
36
+ });
37
+ await fetchAndDisplayReleases(accountId, projectName, {
38
+ limit: options.limit,
39
+ after: paging.next.after,
40
+ });
41
+ }
42
+ }
43
+ async function handler(args) {
44
+ const { derivedAccountId, limit, json: formatOutputAsJson } = args;
45
+ const { projectConfig, projectDir } = await getProjectConfig();
46
+ try {
47
+ validateProjectConfig(projectConfig, projectDir);
48
+ }
49
+ catch (error) {
50
+ logError(error);
51
+ process.exit(EXIT_CODES.ERROR);
52
+ }
53
+ const projectName = projectConfig.name;
54
+ try {
55
+ if (formatOutputAsJson) {
56
+ const { data } = await listReleases(derivedAccountId, projectName, {
57
+ limit,
58
+ });
59
+ uiLogger.json(data);
60
+ }
61
+ else {
62
+ await fetchAndDisplayReleases(derivedAccountId, projectName, { limit });
63
+ }
64
+ }
65
+ catch (e) {
66
+ if (isPromptExitError(e)) {
67
+ throw e;
68
+ }
69
+ if (isHubSpotHttpError(e) && e.status === 404) {
70
+ uiLogger.error(commands.project.release.list.errors.projectNotFound(derivedAccountId, projectName));
71
+ }
72
+ else {
73
+ logError(e, new ApiErrorContext({
74
+ accountId: derivedAccountId,
75
+ request: 'project release list',
76
+ }));
77
+ }
78
+ process.exit(EXIT_CODES.ERROR);
79
+ }
80
+ process.exit(EXIT_CODES.SUCCESS);
81
+ }
82
+ function projectReleaseListBuilder(yargs) {
83
+ yargs.options({
84
+ limit: {
85
+ describe: commands.project.release.list.options.limit,
86
+ type: 'number',
87
+ },
88
+ });
89
+ yargs.example([
90
+ ['$0 project release list', commands.project.release.list.examples.default],
91
+ [
92
+ '$0 project release list --limit=5',
93
+ commands.project.release.list.examples.withLimit,
94
+ ],
95
+ ]);
96
+ return yargs;
97
+ }
98
+ const builder = makeYargsBuilder(projectReleaseListBuilder, command, verboseDescribe, {
99
+ useGlobalOptions: true,
100
+ useConfigOptions: true,
101
+ useAccountOptions: true,
102
+ useEnvironmentOptions: true,
103
+ useJSONOutputOptions: true,
104
+ });
105
+ const projectReleaseListCommand = {
106
+ command,
107
+ describe,
108
+ builder,
109
+ handler: makeWrappedYargsHandler('project-release-list', handler),
110
+ };
111
+ export default projectReleaseListCommand;
@@ -0,0 +1,3 @@
1
+ import { YargsCommandModuleBucket } from '../../types/Yargs.js';
2
+ declare const projectReleaseCommand: YargsCommandModuleBucket;
3
+ export default projectReleaseCommand;
@@ -0,0 +1,20 @@
1
+ import create from './release/create.js';
2
+ import info from './release/info.js';
3
+ import list from './release/list.js';
4
+ import { makeYargsBuilder } from '../../lib/yargsUtils.js';
5
+ // import { commands } from '../../lang/en.js';
6
+ const command = 'release';
7
+ // const describe = commands.project.release.describe;
8
+ const describe = undefined;
9
+ function projectReleaseBuilder(yargs) {
10
+ yargs.command(create).command(info).command(list).demandCommand(1, '');
11
+ return yargs;
12
+ }
13
+ const builder = makeYargsBuilder(projectReleaseBuilder, command, describe);
14
+ const projectReleaseCommand = {
15
+ command,
16
+ describe,
17
+ builder,
18
+ handler: () => { },
19
+ };
20
+ export default projectReleaseCommand;
@@ -6,7 +6,7 @@ import { promptUser } from '../../lib/prompts/promptUtils.js';
6
6
  import path from 'path';
7
7
  import { commands } from '../../lang/en.js';
8
8
  import { uiLogger } from '../../lib/ui/logger.js';
9
- import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
9
+ import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler.js';
10
10
  import { logError } from '../../lib/errorHandlers/index.js';
11
11
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
12
12
  const command = 'update-deps [packages..]';
@@ -77,7 +77,7 @@ const builder = makeYargsBuilder(projectUpdateDepsBuilder, command, describe, {
77
77
  const projectUpdateDepsCommand = {
78
78
  command,
79
79
  describe,
80
- handler: makeYargsHandlerWithUsageTracking('project-update-deps', handler),
80
+ handler: makeWrappedYargsHandler('project-update-deps', handler),
81
81
  builder,
82
82
  };
83
83
  export default projectUpdateDepsCommand;
@@ -4,7 +4,10 @@ export type ProjectUploadArgs = CommonArgs & JSONOutputArgs & {
4
4
  message: string;
5
5
  m: string;
6
6
  skipValidation: boolean;
7
+ skipNpmAudit: boolean;
7
8
  profile?: string;
9
+ preview: boolean;
10
+ target?: number;
8
11
  };
9
12
  declare const projectUploadCommand: YargsCommandModule<unknown, ProjectUploadArgs>;
10
13
  export default projectUploadCommand;
@@ -8,17 +8,32 @@ 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';
10
10
  import { displayWarnLogs, pollProjectBuildAndDeploy, } from '../../lib/projects/pollProjectBuildAndDeploy.js';
11
- import { commands } from '../../lang/en.js';
11
+ import { triggerAndPollPreview } from '../../lib/projects/preview.js';
12
+ import { commands, lib } from '../../lang/en.js';
12
13
  import { PROJECT_ERROR_TYPES } from '../../lib/constants.js';
13
14
  import { logError, ApiErrorContext } from '../../lib/errorHandlers/index.js';
14
15
  import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
15
- import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
16
+ import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler.js';
16
17
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
17
18
  import { projectProfilePrompt } from '../../lib/prompts/projectProfilePrompt.js';
18
19
  const command = 'upload';
19
20
  const describe = commands.project.upload.describe;
21
+ async function handlePreview(accountId, projectId, buildId, targetPortalId) {
22
+ if (!projectId) {
23
+ uiLogger.warn(lib.projectPreview.missingProjectId);
24
+ return;
25
+ }
26
+ const previewResult = await triggerAndPollPreview(accountId, projectId, buildId, targetPortalId);
27
+ if (!previewResult.succeeded) {
28
+ uiLogger.warn(lib.projectPreview.warning);
29
+ }
30
+ return {
31
+ releaseTag: previewResult.releaseTag,
32
+ succeeded: previewResult.succeeded,
33
+ };
34
+ }
20
35
  async function handler(args) {
21
- const { forceCreate, message, derivedAccountId, skipValidation, formatOutputAsJson, profile: profileOption, useEnv: useEnvOption, exit, addUsageMetadata, } = args;
36
+ const { forceCreate, message, derivedAccountId, skipValidation, skipNpmAudit, formatOutputAsJson, profile: profileOption, useEnv: useEnvOption, preview, target: targetPortalId, exit, addUsageMetadata, } = args;
22
37
  const jsonOutput = {};
23
38
  const { projectConfig, projectDir } = await getProjectConfig();
24
39
  try {
@@ -56,16 +71,19 @@ async function handler(args) {
56
71
  assetType: projectConfig.platformVersion,
57
72
  });
58
73
  try {
59
- const { result, uploadError } = await handleProjectUpload({
74
+ const { result, uploadError, projectId } = await handleProjectUpload({
60
75
  accountId: targetAccountId,
61
76
  projectConfig,
62
77
  projectDir,
63
- callbackFunc: pollProjectBuildAndDeploy,
78
+ callbackFunc: preview
79
+ ? (...args) => pollProjectBuildAndDeploy(...args, { skipDeploy: true })
80
+ : pollProjectBuildAndDeploy,
64
81
  uploadMessage: message,
65
82
  forceCreate,
66
83
  isUploadCommand: true,
67
84
  sendIR: !isLegacyProject(projectConfig.platformVersion),
68
85
  skipValidation,
86
+ skipNpmAudit,
69
87
  profile: profileName,
70
88
  });
71
89
  if (uploadError) {
@@ -84,18 +102,37 @@ async function handler(args) {
84
102
  }
85
103
  return exit(EXIT_CODES.ERROR);
86
104
  }
87
- if (result && result.succeeded && !result.buildResult.isAutoDeployEnabled) {
105
+ if (result &&
106
+ result.succeeded &&
107
+ (!result.buildResult.isAutoDeployEnabled || preview)) {
88
108
  uiLogger.log(chalk.bold(commands.project.upload.logs.buildSucceeded(result.buildId)));
89
- uiLogger.log(commands.project.upload.logs.autoDeployDisabled(`hs project deploy --build=${result.buildId}`));
90
- logFeedbackMessage(result.buildId);
109
+ if (!preview) {
110
+ uiLogger.log(commands.project.upload.logs.autoDeployDisabled(`hs project deploy --build=${result.buildId}`));
111
+ logFeedbackMessage(result.buildId);
112
+ }
91
113
  await displayWarnLogs(targetAccountId, projectConfig.name, result.buildId);
92
114
  }
115
+ if (result && result.succeeded && preview && targetPortalId) {
116
+ const previewJson = await handlePreview(targetAccountId, projectId, result.buildId, targetPortalId);
117
+ if (previewJson && formatOutputAsJson) {
118
+ jsonOutput.preview = previewJson;
119
+ }
120
+ }
93
121
  if (result && result.succeeded && formatOutputAsJson) {
94
122
  jsonOutput.buildId = result.buildId;
95
123
  if (result.deployResult) {
96
124
  jsonOutput.deployId = result.deployResult.deployId;
97
125
  }
98
126
  }
127
+ if (result && !result.succeeded) {
128
+ if (formatOutputAsJson) {
129
+ uiLogger.json(jsonOutput);
130
+ }
131
+ return exit(EXIT_CODES.ERROR);
132
+ }
133
+ if (!result && !uploadError) {
134
+ return exit(EXIT_CODES.ERROR);
135
+ }
99
136
  }
100
137
  catch (e) {
101
138
  logError(e, new ApiErrorContext({
@@ -127,11 +164,37 @@ function projectUploadBuilder(yargs) {
127
164
  hidden: true,
128
165
  default: false,
129
166
  },
167
+ 'skip-npm-audit': {
168
+ describe: commands.project.upload.options.skipNpmAudit.describe,
169
+ type: 'boolean',
170
+ default: false,
171
+ },
130
172
  profile: {
131
173
  type: 'string',
132
174
  alias: 'p',
133
175
  describe: commands.project.upload.options.profile.describe,
134
176
  },
177
+ preview: {
178
+ describe: commands.project.upload.options.preview.describe,
179
+ type: 'boolean',
180
+ default: false,
181
+ hidden: true,
182
+ },
183
+ target: {
184
+ describe: commands.project.upload.options.target.describe,
185
+ type: 'number',
186
+ requiresArg: true,
187
+ hidden: true,
188
+ },
189
+ });
190
+ yargs.check(argv => {
191
+ if (argv.preview && argv.target == null) {
192
+ throw new Error(commands.project.upload.errors.previewRequiresTarget);
193
+ }
194
+ if (argv.target != null && !argv.preview) {
195
+ throw new Error(commands.project.upload.errors.targetRequiresPreview);
196
+ }
197
+ return true;
135
198
  });
136
199
  yargs.conflicts('profile', 'account');
137
200
  yargs.example([
@@ -140,6 +203,11 @@ function projectUploadBuilder(yargs) {
140
203
  '$0 project upload --profile=profileName',
141
204
  commands.project.upload.examples.withProfile,
142
205
  ],
206
+ // TODO: Unhide when 2026.09 ships
207
+ // [
208
+ // '$0 project upload --preview --target=12345',
209
+ // commands.project.upload.examples.withPreview,
210
+ // ],
143
211
  ]);
144
212
  return yargs;
145
213
  }
@@ -153,7 +221,7 @@ const builder = makeYargsBuilder(projectUploadBuilder, command, describe, {
153
221
  const projectUploadCommand = {
154
222
  command,
155
223
  describe,
156
- handler: makeYargsHandlerWithUsageTracking('project-upload', handler),
224
+ handler: makeWrappedYargsHandler('project-upload', handler),
157
225
  builder,
158
226
  };
159
227
  export default projectUploadCommand;
@@ -4,7 +4,7 @@ import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
4
4
  import { uiLogger } from '../../lib/ui/logger.js';
5
5
  import { getProjectConfig, validateProjectConfig, } from '../../lib/projects/config.js';
6
6
  import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
7
- import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
7
+ import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler.js';
8
8
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
9
9
  import { validateSourceDirectory, handleTranslate, } from '../../lib/projects/upload.js';
10
10
  import { commands } from '../../lang/en.js';
@@ -150,7 +150,7 @@ const builder = makeYargsBuilder(projectValidateBuilder, command, describe, {
150
150
  const projectValidateCommand = {
151
151
  command,
152
152
  describe,
153
- handler: makeYargsHandlerWithUsageTracking('project-validate', handler),
153
+ handler: makeWrappedYargsHandler('project-validate', handler),
154
154
  builder,
155
155
  };
156
156
  export default projectValidateCommand;