@hubspot/cli 7.7.35-experimental.0 → 7.8.0-beta.1
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.
- package/bin/cli.js +31 -25
- package/commands/__tests__/auth.test.js +5 -0
- package/commands/__tests__/doctor.test.js +16 -16
- package/commands/__tests__/getStarted.test.js +2 -2
- package/commands/__tests__/mcp.test.js +1 -1
- package/commands/__tests__/project.test.js +2 -3
- package/commands/account/auth.js +1 -0
- package/commands/account/clean.js +18 -27
- package/commands/account/createOverride.js +13 -31
- package/commands/account/info.js +20 -31
- package/commands/account/list.js +16 -22
- package/commands/account/remove.js +12 -20
- package/commands/account/removeOverride.js +11 -21
- package/commands/account/rename.js +6 -9
- package/commands/account/use.js +12 -26
- package/commands/account.js +2 -2
- package/commands/app/__tests__/migrate.test.js +5 -6
- package/commands/app/migrate.js +13 -19
- package/commands/app/secret/add.js +2 -1
- package/commands/app/secret/delete.js +2 -1
- package/commands/app/secret/list.js +2 -1
- package/commands/app/secret/update.js +2 -1
- package/commands/app/secret.js +2 -1
- package/commands/app.js +2 -2
- package/commands/auth.d.ts +1 -0
- package/commands/auth.js +17 -7
- package/commands/cms/convertFields.js +7 -9
- package/commands/cms/getReactModule.js +9 -14
- package/commands/cms/lighthouseScore.js +33 -36
- package/commands/cms.js +2 -2
- package/commands/completion.js +3 -3
- package/commands/config/set.d.ts +1 -1
- package/commands/config/set.js +64 -37
- package/commands/config.js +2 -2
- package/commands/create.js +2 -2
- package/commands/customObject/create.js +10 -12
- package/commands/customObject/schema/create.js +9 -11
- package/commands/customObject/schema/delete.js +16 -16
- package/commands/customObject/schema/fetch-all.js +12 -11
- package/commands/customObject/schema/fetch.js +15 -15
- package/commands/customObject/schema/list.js +4 -4
- package/commands/customObject/schema/update.js +13 -13
- package/commands/customObject/schema.js +2 -2
- package/commands/customObject.js +6 -7
- package/commands/doctor.js +8 -11
- package/commands/feedback.js +8 -13
- package/commands/fetch.js +8 -8
- package/commands/filemanager/fetch.js +7 -7
- package/commands/filemanager/upload.js +15 -34
- package/commands/filemanager.js +2 -2
- package/commands/function/deploy.js +11 -29
- package/commands/function/list.js +8 -8
- package/commands/function/server.js +9 -11
- package/commands/function.d.ts +1 -1
- package/commands/function.js +2 -2
- package/commands/getStarted.d.ts +0 -2
- package/commands/getStarted.js +4 -4
- package/commands/hubdb/clear.js +7 -15
- package/commands/hubdb/create.js +9 -15
- package/commands/hubdb/delete.js +8 -15
- package/commands/hubdb/fetch.js +6 -9
- package/commands/hubdb.d.ts +1 -1
- package/commands/hubdb.js +2 -2
- package/commands/init.js +2 -3
- package/commands/lint.js +16 -16
- package/commands/list.js +8 -14
- package/commands/logs.js +14 -20
- package/commands/mcp/__tests__/setup.test.js +2 -2
- package/commands/mcp/setup.js +11 -2
- package/commands/mcp.js +3 -3
- package/commands/mv.js +6 -17
- package/commands/open.js +5 -5
- package/commands/project/__tests__/add.test.js +15 -13
- package/commands/project/__tests__/create.test.js +6 -6
- package/commands/project/__tests__/deploy.test.js +3 -7
- package/commands/project/__tests__/devUnifiedFlow.test.js +2 -4
- package/commands/project/__tests__/installDeps.test.js +8 -8
- package/commands/project/__tests__/list.test.js +31 -0
- package/commands/project/__tests__/logs.test.js +1 -4
- package/commands/project/__tests__/migrate.test.js +7 -7
- package/commands/project/__tests__/migrateApp.test.js +3 -7
- package/commands/project/__tests__/profile.test.js +1 -1
- package/commands/project/__tests__/validate.test.js +98 -0
- package/commands/project/add.d.ts +2 -2
- package/commands/project/add.js +7 -10
- package/commands/project/cloneApp.js +14 -19
- package/commands/project/create.js +3 -10
- package/commands/project/deploy.js +5 -5
- package/commands/project/dev/deprecatedFlow.js +9 -18
- package/commands/project/dev/index.js +21 -18
- package/commands/project/dev/unifiedFlow.js +14 -7
- package/commands/project/download.js +15 -16
- package/commands/project/installDeps.d.ts +2 -2
- package/commands/project/installDeps.js +9 -9
- package/commands/project/list.d.ts +4 -0
- package/commands/project/list.js +62 -0
- package/commands/project/listBuilds.js +12 -21
- package/commands/project/logs.js +21 -24
- package/commands/project/migrate.js +46 -15
- package/commands/project/migrateApp.js +10 -17
- package/commands/project/open.js +6 -14
- package/commands/project/profile/add.js +3 -3
- package/commands/project/profile/delete.js +1 -2
- package/commands/project/profile.js +2 -3
- package/commands/project/upload.js +16 -25
- package/commands/project/validate.js +7 -7
- package/commands/project/watch.js +13 -22
- package/commands/project.js +4 -3
- package/commands/sandbox/__tests__/create.test.js +5 -5
- package/commands/sandbox/create.js +22 -32
- package/commands/sandbox/delete.js +39 -64
- package/commands/sandbox.js +2 -2
- package/commands/secret/addSecret.js +7 -17
- package/commands/secret/deleteSecret.js +10 -20
- package/commands/secret/listSecret.js +8 -10
- package/commands/secret/updateSecret.js +9 -17
- package/commands/secret.js +2 -2
- package/commands/testAccount/__tests__/delete.test.js +2 -4
- package/commands/testAccount/create.js +2 -2
- package/commands/testAccount/delete.d.ts +4 -3
- package/commands/testAccount/delete.js +155 -14
- package/commands/testAccount/importData.d.ts +1 -1
- package/commands/testAccount/importData.js +1 -1
- package/commands/testAccount.js +1 -1
- package/commands/theme/preview.js +1 -4
- package/lang/en.d.ts +364 -110
- package/lang/en.js +409 -158
- package/lang/en.lyaml +4 -4
- package/lib/__tests__/buildAccount.test.js +4 -3
- package/lib/__tests__/commonOpts.test.js +1 -1
- package/lib/__tests__/dependencyManagement.test.js +1 -1
- package/lib/__tests__/developerTestAccounts.test.js +3 -3
- package/lib/__tests__/npm.test.js +1 -1
- package/lib/__tests__/oauth.test.js +4 -4
- package/lib/__tests__/process.test.js +10 -5
- package/lib/__tests__/sandboxSync.test.js +8 -8
- package/lib/__tests__/sandboxes.test.js +8 -8
- package/lib/__tests__/serverlessLogs.test.js +1 -1
- package/lib/__tests__/usageTracking.test.js +5 -5
- package/lib/__tests__/validation.test.js +2 -1
- package/lib/__tests__/yargsUtils.test.js +83 -9
- package/lib/app/__tests__/migrate.test.js +19 -56
- package/lib/app/__tests__/migrate_legacy.test.js +1 -1
- package/lib/app/migrate.d.ts +2 -8
- package/lib/app/migrate.js +6 -81
- package/lib/app/migrate_legacy.js +20 -24
- package/lib/buildAccount.d.ts +2 -2
- package/lib/buildAccount.js +32 -64
- package/lib/commonOpts.d.ts +1 -1
- package/lib/commonOpts.js +25 -22
- package/lib/configMigrate.js +88 -9
- package/lib/configOptions.js +7 -0
- package/lib/constants.d.ts +21 -1
- package/lib/constants.js +25 -1
- package/lib/dependencyManagement.js +9 -27
- package/lib/developerTestAccounts.js +9 -23
- package/lib/doctor/Diagnosis.js +11 -23
- package/lib/doctor/DiagnosticInfoBuilder.js +12 -11
- package/lib/doctor/Doctor.js +42 -90
- package/lib/doctor/__tests__/Doctor.test.js +4 -4
- package/lib/errorHandlers/index.js +12 -20
- package/lib/errorHandlers/suppressError.js +11 -18
- package/lib/lang.js +6 -5
- package/lib/links.d.ts +1 -0
- package/lib/links.js +14 -7
- package/lib/mcp/setup.js +1 -1
- package/lib/middleware/__test__/commandTargetingUtils.test.js +99 -0
- package/lib/middleware/__test__/configMiddleware.test.js +11 -11
- package/lib/middleware/__test__/yargsChecksMiddleware.test.js +6 -8
- package/lib/middleware/commandTargetingUtils.d.ts +8 -0
- package/lib/middleware/commandTargetingUtils.js +74 -0
- package/lib/middleware/configMiddleware.d.ts +1 -1
- package/lib/middleware/configMiddleware.js +21 -81
- package/lib/middleware/fireAlarmMiddleware.js +15 -5
- package/lib/middleware/gitMiddleware.js +5 -1
- package/lib/middleware/notificationsMiddleware.js +5 -11
- package/lib/middleware/yargsChecksMiddleware.js +6 -9
- package/lib/npm.js +2 -2
- package/lib/oauth.js +5 -5
- package/lib/process.js +5 -4
- package/lib/projects/__tests__/AppDevModeInterface.test.js +87 -90
- package/lib/projects/__tests__/LocalDevProcess.test.js +231 -19
- package/lib/projects/__tests__/LocalDevWebsocketServer.test.js +89 -63
- package/lib/projects/__tests__/deploy.test.js +73 -8
- package/lib/projects/__tests__/localDevProjectHelpers.test.js +6 -2
- package/lib/projects/__tests__/platformVersion.test.js +8 -8
- package/lib/projects/__tests__/projects.test.js +12 -12
- package/lib/projects/__tests__/structure.test.js +3 -3
- package/lib/projects/__tests__/upload.test.d.ts +1 -0
- package/lib/projects/__tests__/upload.test.js +82 -0
- package/lib/projects/add/__tests__/legacyAddComponent.test.js +6 -6
- package/lib/projects/add/__tests__/v2AddComponent.test.d.ts +1 -0
- package/lib/projects/add/__tests__/{v3AddComponent.test.js → v2AddComponent.test.js} +39 -39
- package/lib/projects/add/{v3AddComponent.d.ts → v2AddComponent.d.ts} +1 -1
- package/lib/projects/add/{v3AddComponent.js → v2AddComponent.js} +5 -5
- package/lib/projects/create/__tests__/legacy.test.js +5 -5
- package/lib/projects/create/__tests__/v2.test.d.ts +1 -0
- package/lib/projects/create/__tests__/{v3.test.js → v2.test.js} +82 -7
- package/lib/projects/create/index.js +4 -4
- package/lib/projects/create/legacy.js +2 -2
- package/lib/projects/create/{v3.d.ts → v2.d.ts} +3 -3
- package/lib/projects/create/{v3.js → v2.js} +13 -11
- package/lib/projects/deploy.d.ts +1 -1
- package/lib/projects/deploy.js +2 -2
- package/lib/projects/localDev/AppDevModeInterface.d.ts +10 -1
- package/lib/projects/localDev/AppDevModeInterface.js +118 -89
- package/lib/projects/localDev/DevServerManager.d.ts +11 -29
- package/lib/projects/localDev/DevServerManager.js +19 -61
- package/lib/projects/localDev/DevServerManager_DEPRECATED.d.ts +40 -0
- package/lib/projects/localDev/DevServerManager_DEPRECATED.js +120 -0
- package/lib/projects/localDev/LocalDevLogger.d.ts +4 -0
- package/lib/projects/localDev/LocalDevLogger.js +27 -6
- package/lib/projects/localDev/{LocalDevManager.js → LocalDevManager_DEPRECATED.js} +10 -11
- package/lib/projects/localDev/LocalDevProcess.d.ts +7 -5
- package/lib/projects/localDev/LocalDevProcess.js +93 -21
- package/lib/projects/localDev/LocalDevState.d.ts +12 -8
- package/lib/projects/localDev/LocalDevState.js +27 -17
- package/lib/projects/localDev/LocalDevWebsocketServer.d.ts +6 -1
- package/lib/projects/localDev/LocalDevWebsocketServer.js +94 -33
- package/lib/projects/localDev/helpers/account.d.ts +1 -1
- package/lib/projects/localDev/helpers/account.js +2 -2
- package/lib/projects/localDev/helpers/project.d.ts +1 -0
- package/lib/projects/localDev/helpers/project.js +44 -4
- package/lib/projects/localDev/localDevWebsocketServerUtils.d.ts +7 -0
- package/lib/projects/localDev/localDevWebsocketServerUtils.js +19 -0
- package/lib/projects/platformVersion.d.ts +1 -1
- package/lib/projects/platformVersion.js +1 -1
- package/lib/projects/pollProjectBuildAndDeploy.js +4 -4
- package/lib/projects/structure.js +6 -6
- package/lib/projects/upload.d.ts +1 -1
- package/lib/projects/upload.js +17 -8
- package/lib/projects/urls.d.ts +0 -1
- package/lib/projects/urls.js +0 -3
- package/lib/prompts/__tests__/downloadProjectPrompt.test.js +1 -0
- package/lib/prompts/__tests__/projectAddPrompt.test.js +10 -10
- package/lib/prompts/accountNamePrompt.js +14 -19
- package/lib/prompts/accountsPrompt.js +2 -2
- package/lib/prompts/cmsFieldPrompt.js +2 -2
- package/lib/prompts/createApiSamplePrompt.js +5 -5
- package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +10 -1
- package/lib/prompts/createFunctionPrompt.js +14 -14
- package/lib/prompts/createModulePrompt.js +9 -9
- package/lib/prompts/createTemplatePrompt.js +2 -2
- package/lib/prompts/downloadProjectPrompt.js +5 -8
- package/lib/prompts/installAppPrompt.d.ts +1 -6
- package/lib/prompts/installAppPrompt.js +1 -6
- package/lib/prompts/personalAccessKeyPrompt.js +3 -3
- package/lib/prompts/previewPrompt.js +6 -6
- package/lib/prompts/projectAddPrompt.d.ts +2 -2
- package/lib/prompts/projectAddPrompt.js +9 -2
- package/lib/prompts/projectDevTargetAccountPrompt.js +20 -32
- package/lib/prompts/projectNamePrompt.js +4 -8
- package/lib/prompts/projectsLogsPrompt.js +2 -4
- package/lib/prompts/promptUtils.js +30 -9
- package/lib/prompts/sandboxesPrompt.js +7 -7
- package/lib/prompts/secretPrompt.js +3 -3
- package/lib/prompts/selectAppPrompt.js +3 -3
- package/lib/prompts/selectHubDBTablePrompt.js +9 -13
- package/lib/prompts/selectProjectTemplatePrompt.js +2 -0
- package/lib/prompts/selectPublicAppForMigrationPrompt.js +15 -19
- package/lib/prompts/setAsDefaultAccountPrompt.js +4 -8
- package/lib/prompts/uploadPrompt.js +5 -5
- package/lib/sandboxSync.js +24 -41
- package/lib/sandboxes.js +19 -47
- package/lib/schema.js +3 -3
- package/lib/serverlessLogs.js +11 -13
- package/lib/theme/__tests__/migrate.test.d.ts +1 -0
- package/lib/theme/__tests__/migrate.test.js +233 -0
- package/lib/theme/migrate.d.ts +13 -0
- package/lib/theme/migrate.js +90 -0
- package/lib/ui/SpinniesManager.d.ts +2 -0
- package/lib/ui/SpinniesManager.js +7 -0
- package/lib/ui/boxen.js +1 -2
- package/lib/ui/git.js +13 -10
- package/lib/ui/index.d.ts +4 -0
- package/lib/ui/index.js +47 -38
- package/lib/ui/serverlessFunctionLogs.js +9 -7
- package/lib/ui/uiMessages.d.ts +72 -0
- package/lib/ui/uiMessages.js +75 -0
- package/lib/usageTracking.js +8 -8
- package/lib/validation.js +20 -23
- package/lib/yargsUtils.d.ts +1 -1
- package/lib/yargsUtils.js +12 -5
- package/mcp-server/tools/cms/HsCreateModuleTool.d.ts +2 -2
- package/mcp-server/tools/index.js +4 -0
- package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +2 -2
- package/mcp-server/tools/project/CreateProjectTool.d.ts +2 -2
- package/mcp-server/tools/project/DocsSearchTool.d.ts +4 -1
- package/mcp-server/tools/project/DocsSearchTool.js +5 -5
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.d.ts +23 -0
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +68 -0
- package/mcp-server/tools/project/GetApplicationInfoTool.d.ts +11 -0
- package/mcp-server/tools/project/GetApplicationInfoTool.js +49 -0
- package/mcp-server/tools/project/GetConfigValuesTool.d.ts +4 -1
- package/mcp-server/tools/project/GetConfigValuesTool.js +12 -6
- package/mcp-server/tools/project/GuidedWalkthroughTool.d.ts +2 -2
- package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +1 -1
- package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +12 -10
- package/mcp-server/tools/project/__tests__/GetApiUsagePatternsByAppIdTool.test.d.ts +1 -0
- package/mcp-server/tools/project/__tests__/GetApiUsagePatternsByAppIdTool.test.js +169 -0
- package/mcp-server/tools/project/__tests__/GetApplicationInfoTool.test.d.ts +1 -0
- package/mcp-server/tools/project/__tests__/GetApplicationInfoTool.test.js +115 -0
- package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +8 -7
- package/mcp-server/utils/__tests__/cliConfig.test.d.ts +1 -0
- package/mcp-server/utils/__tests__/cliConfig.test.js +110 -0
- package/mcp-server/utils/cliConfig.d.ts +1 -0
- package/mcp-server/utils/cliConfig.js +12 -0
- package/mcp-server/utils/toolUsageTracking.js +2 -2
- package/package.json +8 -7
- package/types/LocalDev.d.ts +19 -3
- package/ui/index.js +1 -1
- package/lib/middleware/__test__/utils.test.js +0 -51
- package/lib/middleware/utils.d.ts +0 -8
- package/lib/middleware/utils.js +0 -14
- package/lib/projects/localDev/DevServerManagerV2.d.ts +0 -22
- package/lib/projects/localDev/DevServerManagerV2.js +0 -81
- /package/{lib/middleware/__test__/utils.test.d.ts → commands/project/__tests__/list.test.d.ts} +0 -0
- /package/{lib/projects/add/__tests__/v3AddComponent.test.d.ts → commands/project/__tests__/validate.test.d.ts} +0 -0
- /package/lib/{projects/create/__tests__/v3.test.d.ts → middleware/__test__/commandTargetingUtils.test.d.ts} +0 -0
- /package/lib/projects/localDev/{LocalDevManager.d.ts → LocalDevManager_DEPRECATED.d.ts} +0 -0
|
@@ -2,7 +2,7 @@ import { legacyAddComponent } from '../legacyAddComponent.js';
|
|
|
2
2
|
import { findProjectComponents } from '../../structure.js';
|
|
3
3
|
import { getProjectComponentListFromRepo } from '../../create/legacy.js';
|
|
4
4
|
import { projectAddPrompt } from '../../../prompts/projectAddPrompt.js';
|
|
5
|
-
import {
|
|
5
|
+
import { uiLogger } from '../../../ui/logger.js';
|
|
6
6
|
import { cloneGithubRepo } from '@hubspot/local-dev-lib/github';
|
|
7
7
|
import { trackCommandUsage } from '../../../usageTracking.js';
|
|
8
8
|
import { ComponentTypes, } from '../../../../types/Projects.js';
|
|
@@ -10,13 +10,13 @@ import { commands } from '../../../../lang/en.js';
|
|
|
10
10
|
vi.mock('../../structure');
|
|
11
11
|
vi.mock('../../create/legacy');
|
|
12
12
|
vi.mock('../../../prompts/projectAddPrompt');
|
|
13
|
-
vi.mock('
|
|
13
|
+
vi.mock('../../../ui/logger.js');
|
|
14
14
|
vi.mock('@hubspot/local-dev-lib/github');
|
|
15
15
|
vi.mock('../../../usageTracking.js');
|
|
16
16
|
const mockedFindProjectComponents = vi.mocked(findProjectComponents);
|
|
17
17
|
const mockedGetProjectComponentListFromRepo = vi.mocked(getProjectComponentListFromRepo);
|
|
18
18
|
const mockedProjectAddPrompt = vi.mocked(projectAddPrompt);
|
|
19
|
-
const
|
|
19
|
+
const mockedUiLogger = vi.mocked(uiLogger);
|
|
20
20
|
const mockedCloneGithubRepo = vi.mocked(cloneGithubRepo);
|
|
21
21
|
const mockedTrackCommandUsage = vi.mocked(trackCommandUsage);
|
|
22
22
|
describe('lib/projects/add/legacyAddComponent', () => {
|
|
@@ -75,8 +75,8 @@ describe('lib/projects/add/legacyAddComponent', () => {
|
|
|
75
75
|
expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
|
|
76
76
|
type: 'module',
|
|
77
77
|
}, accountId);
|
|
78
|
-
expect(
|
|
79
|
-
expect(
|
|
78
|
+
expect(mockedUiLogger.log).toHaveBeenCalledWith(commands.project.add.creatingComponent('test-project'));
|
|
79
|
+
expect(mockedUiLogger.success).toHaveBeenCalledWith(commands.project.add.success('new-component'));
|
|
80
80
|
});
|
|
81
81
|
it('throws an error when project contains a public app', async () => {
|
|
82
82
|
const mockComponents = [
|
|
@@ -206,7 +206,7 @@ describe('lib/projects/add/legacyAddComponent', () => {
|
|
|
206
206
|
mockedCloneGithubRepo.mockRejectedValue(new Error('Clone failed'));
|
|
207
207
|
await expect(legacyAddComponent(mockArgs, projectDir, mockProjectConfig, accountId)).rejects.toThrow(commands.project.add.error.failedToDownloadComponent);
|
|
208
208
|
expect(mockedCloneGithubRepo).toHaveBeenCalled();
|
|
209
|
-
expect(
|
|
209
|
+
expect(mockedUiLogger.success).not.toHaveBeenCalled();
|
|
210
210
|
});
|
|
211
211
|
it('calls trackCommandUsage with correct component type', async () => {
|
|
212
212
|
const mockComponents = [
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
-
import {
|
|
2
|
+
import { v2AddComponent } from '../v2AddComponent.js';
|
|
3
3
|
import { getConfigForPlatformVersion } from '../../create/legacy.js';
|
|
4
|
-
import {
|
|
4
|
+
import { createV2App } from '../../create/v2.js';
|
|
5
5
|
import { confirmPrompt } from '../../../prompts/promptUtils.js';
|
|
6
|
-
import {
|
|
6
|
+
import { projectAddPromptV2 } from '../../../prompts/projectAddPrompt.js';
|
|
7
7
|
import { cloneGithubRepo } from '@hubspot/local-dev-lib/github';
|
|
8
|
-
import {
|
|
8
|
+
import { uiLogger } from '../../../ui/logger.js';
|
|
9
9
|
import { getProjectMetadata } from '@hubspot/project-parsing-lib/src/lib/project.js';
|
|
10
10
|
import { trackCommandUsage } from '../../../usageTracking.js';
|
|
11
11
|
import { commands } from '../../../../lang/en.js';
|
|
12
12
|
vi.mock('fs');
|
|
13
13
|
vi.mock('../../../prompts/promptUtils');
|
|
14
14
|
vi.mock('../../create/legacy');
|
|
15
|
-
vi.mock('../../create/
|
|
15
|
+
vi.mock('../../create/v2');
|
|
16
16
|
vi.mock('../../../prompts/projectAddPrompt');
|
|
17
17
|
vi.mock('@hubspot/local-dev-lib/github');
|
|
18
|
-
vi.mock('
|
|
18
|
+
vi.mock('../../../ui/logger.js');
|
|
19
19
|
vi.mock('@hubspot/project-parsing-lib/src/lib/project');
|
|
20
20
|
vi.mock('../../../usageTracking');
|
|
21
21
|
const mockedFs = vi.mocked(fs);
|
|
22
22
|
const mockedGetConfigForPlatformVersion = vi.mocked(getConfigForPlatformVersion);
|
|
23
23
|
const mockedConfirmPrompt = vi.mocked(confirmPrompt);
|
|
24
|
-
const
|
|
25
|
-
const
|
|
24
|
+
const mockedCreateV2App = vi.mocked(createV2App);
|
|
25
|
+
const mockedProjectAddPromptV2 = vi.mocked(projectAddPromptV2);
|
|
26
26
|
const mockedCloneGithubRepo = vi.mocked(cloneGithubRepo);
|
|
27
|
-
const
|
|
27
|
+
const mockedUiLogger = vi.mocked(uiLogger);
|
|
28
28
|
const mockedGetProjectMetadata = vi.mocked(getProjectMetadata);
|
|
29
29
|
const mockedTrackCommandUsage = vi.mocked(trackCommandUsage);
|
|
30
|
-
describe('lib/projects/add/
|
|
30
|
+
describe('lib/projects/add/v2AddComponent', () => {
|
|
31
31
|
const mockProjectConfig = {
|
|
32
32
|
name: 'test-project',
|
|
33
33
|
srcDir: 'src',
|
|
34
|
-
platformVersion: '
|
|
34
|
+
platformVersion: '2025.2',
|
|
35
35
|
};
|
|
36
36
|
const mockArgs = {
|
|
37
37
|
name: 'test-component',
|
|
@@ -66,13 +66,13 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
66
66
|
},
|
|
67
67
|
};
|
|
68
68
|
beforeEach(() => {
|
|
69
|
-
|
|
69
|
+
mockedCreateV2App.mockResolvedValue({
|
|
70
70
|
authType: 'oauth',
|
|
71
71
|
distribution: 'private',
|
|
72
72
|
});
|
|
73
73
|
mockedTrackCommandUsage.mockResolvedValue();
|
|
74
74
|
});
|
|
75
|
-
describe('
|
|
75
|
+
describe('v2AddComponent()', () => {
|
|
76
76
|
it('successfully adds a component when app already exists', async () => {
|
|
77
77
|
const mockAppMeta = {
|
|
78
78
|
config: {
|
|
@@ -86,21 +86,21 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
86
86
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
87
87
|
mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadata);
|
|
88
88
|
mockedFs.readFileSync.mockReturnValue(JSON.stringify(mockAppMeta));
|
|
89
|
-
|
|
89
|
+
mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
|
|
90
90
|
mockedCloneGithubRepo.mockResolvedValue(true);
|
|
91
|
-
await
|
|
92
|
-
expect(mockedGetConfigForPlatformVersion).toHaveBeenCalledWith('
|
|
91
|
+
await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
|
|
92
|
+
expect(mockedGetConfigForPlatformVersion).toHaveBeenCalledWith('2025.2');
|
|
93
93
|
expect(mockedGetProjectMetadata).toHaveBeenCalledWith('/path/to/project/src');
|
|
94
|
-
expect(
|
|
94
|
+
expect(mockedProjectAddPromptV2).toHaveBeenCalled();
|
|
95
95
|
expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
|
|
96
96
|
type: 'module',
|
|
97
97
|
}, mockAccountId);
|
|
98
98
|
expect(mockedCloneGithubRepo).toHaveBeenCalledWith(expect.any(String), projectDir, expect.objectContaining({
|
|
99
|
-
sourceDir: ['
|
|
99
|
+
sourceDir: ['2025.2/test-component'],
|
|
100
100
|
hideLogs: true,
|
|
101
101
|
branch: 'main',
|
|
102
102
|
}));
|
|
103
|
-
expect(
|
|
103
|
+
expect(mockedUiLogger.success).toHaveBeenCalled();
|
|
104
104
|
});
|
|
105
105
|
it('creates an app when no app exists and user confirms', async () => {
|
|
106
106
|
const mockProjectMetadataNoApps = {
|
|
@@ -116,15 +116,15 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
116
116
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
117
117
|
mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadataNoApps);
|
|
118
118
|
mockedConfirmPrompt.mockResolvedValue(true);
|
|
119
|
-
|
|
119
|
+
mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
|
|
120
120
|
mockedCloneGithubRepo.mockResolvedValue(true);
|
|
121
|
-
await
|
|
122
|
-
expect(
|
|
121
|
+
await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
|
|
122
|
+
expect(mockedCreateV2App).toHaveBeenCalled();
|
|
123
123
|
expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
|
|
124
124
|
type: 'module',
|
|
125
125
|
}, mockAccountId);
|
|
126
126
|
expect(mockedCloneGithubRepo).toHaveBeenCalledWith(expect.any(String), projectDir, expect.objectContaining({
|
|
127
|
-
sourceDir: ['
|
|
127
|
+
sourceDir: ['2025.2/test-component', '2025.2/app-template'],
|
|
128
128
|
}));
|
|
129
129
|
});
|
|
130
130
|
it('should not call clone', async () => {
|
|
@@ -145,10 +145,10 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
145
145
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
146
146
|
mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadataNoApps);
|
|
147
147
|
mockedConfirmPrompt.mockResolvedValue(true);
|
|
148
|
-
|
|
148
|
+
mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
|
|
149
149
|
mockedCloneGithubRepo.mockResolvedValue(true);
|
|
150
|
-
await
|
|
151
|
-
expect(
|
|
150
|
+
await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
|
|
151
|
+
expect(mockedCreateV2App).not.toHaveBeenCalled();
|
|
152
152
|
expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
|
|
153
153
|
type: '',
|
|
154
154
|
}, mockAccountId);
|
|
@@ -164,7 +164,7 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
164
164
|
};
|
|
165
165
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
166
166
|
mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadataMaxApps);
|
|
167
|
-
await expect(
|
|
167
|
+
await expect(v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId)).rejects.toThrow('This project currently has the maximum number of apps: 1');
|
|
168
168
|
});
|
|
169
169
|
it('throws an error when components list is empty', async () => {
|
|
170
170
|
const mockEmptyConfig = {
|
|
@@ -172,7 +172,7 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
172
172
|
parentComponents: [],
|
|
173
173
|
};
|
|
174
174
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockEmptyConfig);
|
|
175
|
-
await expect(
|
|
175
|
+
await expect(v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId)).rejects.toThrow(commands.project.add.error.failedToFetchComponentList);
|
|
176
176
|
});
|
|
177
177
|
it('throws an error when app meta file cannot be parsed', async () => {
|
|
178
178
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
@@ -180,7 +180,7 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
180
180
|
mockedFs.readFileSync.mockImplementation(() => {
|
|
181
181
|
throw new Error('File read error');
|
|
182
182
|
});
|
|
183
|
-
await expect(
|
|
183
|
+
await expect(v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId)).rejects.toThrow('Unable to parse app file');
|
|
184
184
|
});
|
|
185
185
|
it('throws an error when cloning fails', async () => {
|
|
186
186
|
const mockAppMeta = {
|
|
@@ -195,9 +195,9 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
195
195
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
196
196
|
mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadata);
|
|
197
197
|
mockedFs.readFileSync.mockReturnValue(JSON.stringify(mockAppMeta));
|
|
198
|
-
|
|
198
|
+
mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
|
|
199
199
|
mockedCloneGithubRepo.mockRejectedValue(new Error('Clone failed'));
|
|
200
|
-
await expect(
|
|
200
|
+
await expect(v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId)).rejects.toThrow(commands.project.add.error.failedToDownloadComponent);
|
|
201
201
|
});
|
|
202
202
|
it('should track usage with multiple component types', async () => {
|
|
203
203
|
const mockAppMeta = {
|
|
@@ -219,9 +219,9 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
219
219
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
220
220
|
mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadata);
|
|
221
221
|
mockedFs.readFileSync.mockReturnValue(JSON.stringify(mockAppMeta));
|
|
222
|
-
|
|
222
|
+
mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
|
|
223
223
|
mockedCloneGithubRepo.mockResolvedValue(true);
|
|
224
|
-
await
|
|
224
|
+
await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
|
|
225
225
|
expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
|
|
226
226
|
type: 'module,card',
|
|
227
227
|
}, mockAccountId);
|
|
@@ -243,8 +243,8 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
243
243
|
};
|
|
244
244
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
245
245
|
mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadataNoApps);
|
|
246
|
-
|
|
247
|
-
await
|
|
246
|
+
mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
|
|
247
|
+
await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
|
|
248
248
|
expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
|
|
249
249
|
type: '',
|
|
250
250
|
}, mockAccountId);
|
|
@@ -270,9 +270,9 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
270
270
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
271
271
|
mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadata);
|
|
272
272
|
mockedFs.readFileSync.mockReturnValue(JSON.stringify(mockAppMeta));
|
|
273
|
-
|
|
273
|
+
mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
|
|
274
274
|
mockedCloneGithubRepo.mockResolvedValue(true);
|
|
275
|
-
await
|
|
275
|
+
await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
|
|
276
276
|
expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
|
|
277
277
|
type: 'workflow-action-tool',
|
|
278
278
|
}, mockAccountId);
|
|
@@ -308,9 +308,9 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
308
308
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
309
309
|
mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadata);
|
|
310
310
|
mockedFs.readFileSync.mockReturnValue(JSON.stringify(mockAppMeta));
|
|
311
|
-
|
|
311
|
+
mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
|
|
312
312
|
mockedCloneGithubRepo.mockResolvedValue(true);
|
|
313
|
-
await
|
|
313
|
+
await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
|
|
314
314
|
expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
|
|
315
315
|
type: 'workflow-action-tool,module',
|
|
316
316
|
}, mockAccountId);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { commands, lib } from '../../../lang/en.js';
|
|
2
2
|
import { getConfigForPlatformVersion } from '../create/legacy.js';
|
|
3
|
-
import { calculateComponentTemplateChoices,
|
|
3
|
+
import { calculateComponentTemplateChoices, createV2App, } from '../create/v2.js';
|
|
4
4
|
import { PROJECT_WITH_APP } from '../../constants.js';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import fs from 'fs';
|
|
7
|
-
import {
|
|
7
|
+
import { projectAddPromptV2 } from '../../prompts/projectAddPrompt.js';
|
|
8
8
|
import { HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, DEFAULT_PROJECT_TEMPLATE_BRANCH, } from '../../constants.js';
|
|
9
9
|
import { updateHsMetaFilesWithAutoGeneratedFields, handleComponentCollision, } from '../components.js';
|
|
10
10
|
import { getProjectMetadata, } from '@hubspot/project-parsing-lib/src/lib/project.js';
|
|
@@ -13,7 +13,7 @@ import { cloneGithubRepo } from '@hubspot/local-dev-lib/github';
|
|
|
13
13
|
import { debugError } from '../../errorHandlers/index.js';
|
|
14
14
|
import { uiLogger } from '../../ui/logger.js';
|
|
15
15
|
import { trackCommandUsage } from '../../usageTracking.js';
|
|
16
|
-
export async function
|
|
16
|
+
export async function v2AddComponent(args, projectDir, projectConfig, accountId) {
|
|
17
17
|
uiLogger.log(commands.project.add.creatingComponent(projectConfig.name));
|
|
18
18
|
const config = await getConfigForPlatformVersion(projectConfig.platformVersion);
|
|
19
19
|
const { components, parentComponents } = config;
|
|
@@ -27,7 +27,7 @@ export async function v3AddComponent(args, projectDir, projectConfig, accountId)
|
|
|
27
27
|
const appsMetadata = currentProjectMetadata.components[AppKey];
|
|
28
28
|
const shouldCreateApp = appsMetadata.count === 0;
|
|
29
29
|
if (shouldCreateApp) {
|
|
30
|
-
const { authType, distribution } = await
|
|
30
|
+
const { authType, distribution } = await createV2App(args.auth, args.distribution);
|
|
31
31
|
derivedDistribution = distribution;
|
|
32
32
|
derivedAuthType = authType;
|
|
33
33
|
}
|
|
@@ -47,7 +47,7 @@ export async function v3AddComponent(args, projectDir, projectConfig, accountId)
|
|
|
47
47
|
derivedAuthType = apps[0].config?.auth?.type;
|
|
48
48
|
}
|
|
49
49
|
const componentTemplateChoices = await calculateComponentTemplateChoices(components, derivedAuthType, derivedDistribution, args.derivedAccountId, currentProjectMetadata);
|
|
50
|
-
const projectAddPromptResponse = await
|
|
50
|
+
const projectAddPromptResponse = await projectAddPromptV2(componentTemplateChoices, args.features);
|
|
51
51
|
const componentTypes = projectAddPromptResponse.componentTemplate?.map(componentTemplate => componentTemplate.cliSelector || componentTemplate.type);
|
|
52
52
|
await trackCommandUsage('project-add', {
|
|
53
53
|
type: componentTypes?.join(','),
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { uiLogger } from '../../../ui/logger.js';
|
|
2
2
|
import * as github from '@hubspot/local-dev-lib/api/github';
|
|
3
3
|
import { EXIT_CODES } from '../../../enums/exitCodes.js';
|
|
4
4
|
import { getProjectComponentListFromRepo, getProjectTemplateListFromRepo, } from '../legacy.js';
|
|
5
5
|
import { PROJECT_COMPONENT_TYPES, HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, } from '../../../constants.js';
|
|
6
|
-
vi.mock('
|
|
6
|
+
vi.mock('../../../ui/logger.js');
|
|
7
7
|
vi.mock('@hubspot/local-dev-lib/api/github');
|
|
8
8
|
const mockedFetchRepoFile = vi.mocked(github.fetchRepoFile);
|
|
9
9
|
const repoConfig = {
|
|
@@ -60,14 +60,14 @@ describe('lib/projects/create/legacy', () => {
|
|
|
60
60
|
it('Logs an error and exits the process if the request for the template list fails', async () => {
|
|
61
61
|
mockedFetchRepoFile.mockRejectedValue(new Error('Not found'));
|
|
62
62
|
await getProjectTemplateListFromRepo(HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, 'gh-ref');
|
|
63
|
-
expect(
|
|
63
|
+
expect(uiLogger.error).toHaveBeenCalledWith(expect.stringMatching(/Failed to fetch the config.json file from the target repository/));
|
|
64
64
|
expect(exitMock).toHaveBeenCalledWith(EXIT_CODES.ERROR);
|
|
65
65
|
});
|
|
66
66
|
it('Logs an error and exits the process if there are no projects listed in the repo config', async () => {
|
|
67
67
|
// @ts-expect-error - Mocking AxiosResponse
|
|
68
68
|
mockedFetchRepoFile.mockResolvedValue({});
|
|
69
69
|
await getProjectTemplateListFromRepo(HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, 'gh-ref');
|
|
70
|
-
expect(
|
|
70
|
+
expect(uiLogger.error).toHaveBeenCalledWith(expect.stringMatching(/Unable to find any projects in the target repository's config.json file/));
|
|
71
71
|
expect(exitMock).toHaveBeenCalledWith(EXIT_CODES.ERROR);
|
|
72
72
|
});
|
|
73
73
|
it('Logs an error and exits the process if any of the projects in the repo config are missing required properties', async () => {
|
|
@@ -84,7 +84,7 @@ describe('lib/projects/create/legacy', () => {
|
|
|
84
84
|
},
|
|
85
85
|
});
|
|
86
86
|
await getProjectTemplateListFromRepo(HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, 'gh-ref');
|
|
87
|
-
expect(
|
|
87
|
+
expect(uiLogger.error).toHaveBeenCalledWith(expect.stringMatching(/Found misconfigured projects in the target repository's config.json file/));
|
|
88
88
|
expect(exitMock).toHaveBeenCalledWith(EXIT_CODES.ERROR);
|
|
89
89
|
});
|
|
90
90
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,8 +1,17 @@
|
|
|
1
|
-
import { calculateComponentTemplateChoices } from '../
|
|
2
|
-
|
|
1
|
+
import { calculateComponentTemplateChoices } from '../v2.js';
|
|
2
|
+
import { hasFeature } from '../../../hasFeature.js';
|
|
3
|
+
vi.mock('../../ui/logger.js');
|
|
3
4
|
vi.mock('@hubspot/local-dev-lib/api/github');
|
|
4
|
-
|
|
5
|
+
vi.mock('../../../hasFeature.js');
|
|
6
|
+
const mockHasFeature = vi.mocked(hasFeature);
|
|
7
|
+
describe('lib/projects/create/v2', () => {
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
mockHasFeature.mockResolvedValue(true);
|
|
10
|
+
});
|
|
5
11
|
describe('calculateComponentTemplateChoices()', () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
mockHasFeature.mockClear();
|
|
14
|
+
});
|
|
6
15
|
const mockComponents = [
|
|
7
16
|
{
|
|
8
17
|
label: 'Module Component',
|
|
@@ -30,7 +39,7 @@ describe('lib/projects/create/v3', () => {
|
|
|
30
39
|
const choices = await calculateComponentTemplateChoices(mockComponents, 'oauth', 'private', 123, mockProjectMetadataForChoices);
|
|
31
40
|
expect(choices).toHaveLength(4); // includes separator
|
|
32
41
|
expect(choices[0]).toEqual({
|
|
33
|
-
name: 'Module Component',
|
|
42
|
+
name: 'Module Component [module]',
|
|
34
43
|
value: mockComponents[0],
|
|
35
44
|
});
|
|
36
45
|
expect(choices[2]).toEqual({
|
|
@@ -70,7 +79,7 @@ describe('lib/projects/create/v3', () => {
|
|
|
70
79
|
components: { module: { count: 0, maxCount: 5, hsMetaFiles: [] } },
|
|
71
80
|
});
|
|
72
81
|
expect(choices[0]).toEqual({
|
|
73
|
-
name: 'Unrestricted Component',
|
|
82
|
+
name: 'Unrestricted Component [module]',
|
|
74
83
|
value: componentsWithoutRestrictions[0],
|
|
75
84
|
});
|
|
76
85
|
});
|
|
@@ -94,7 +103,7 @@ describe('lib/projects/create/v3', () => {
|
|
|
94
103
|
const choices = await calculateComponentTemplateChoices(componentWithCliSelector, 'oauth', 'private', 213, projectMetadataWithWorkflowAction);
|
|
95
104
|
expect(choices).toHaveLength(1); // no disabled components
|
|
96
105
|
expect(choices[0]).toEqual({
|
|
97
|
-
name: 'Workflow Action Tool',
|
|
106
|
+
name: 'Workflow Action Tool [workflow-action-tool]',
|
|
98
107
|
value: componentWithCliSelector[0],
|
|
99
108
|
});
|
|
100
109
|
});
|
|
@@ -137,7 +146,7 @@ describe('lib/projects/create/v3', () => {
|
|
|
137
146
|
const choices = await calculateComponentTemplateChoices(componentWithCliSelector, 'oauth', 'private', 123, undefined);
|
|
138
147
|
expect(choices).toHaveLength(1); // no disabled components
|
|
139
148
|
expect(choices[0]).toEqual({
|
|
140
|
-
name: 'Workflow Action Tool',
|
|
149
|
+
name: 'Workflow Action Tool [workflow-action-tool]',
|
|
141
150
|
value: componentWithCliSelector[0],
|
|
142
151
|
});
|
|
143
152
|
});
|
|
@@ -162,5 +171,71 @@ describe('lib/projects/create/v3', () => {
|
|
|
162
171
|
// @ts-expect-error breaking stuff on purpose
|
|
163
172
|
projectMetadataWithoutComponents)).rejects.toThrow();
|
|
164
173
|
});
|
|
174
|
+
it('disables gated components when hasFeature returns false', async () => {
|
|
175
|
+
mockHasFeature.mockResolvedValue(false);
|
|
176
|
+
const gatedComponent = [
|
|
177
|
+
{
|
|
178
|
+
label: 'Workflow Action Tool',
|
|
179
|
+
path: 'workflow-action-tool',
|
|
180
|
+
type: 'workflow-action',
|
|
181
|
+
cliSelector: 'workflow-action-tool',
|
|
182
|
+
supportedAuthTypes: ['oauth'],
|
|
183
|
+
supportedDistributions: ['private'],
|
|
184
|
+
},
|
|
185
|
+
];
|
|
186
|
+
const choices = await calculateComponentTemplateChoices(gatedComponent, 'oauth', 'private', 123, mockProjectMetadataForChoices);
|
|
187
|
+
expect(choices).toHaveLength(3); // includes separators
|
|
188
|
+
expect(choices[1]).toEqual({
|
|
189
|
+
name: expect.stringContaining('Workflow Action Tool'),
|
|
190
|
+
value: gatedComponent[0],
|
|
191
|
+
disabled: expect.stringContaining('does not have access to this feature'),
|
|
192
|
+
});
|
|
193
|
+
expect(mockHasFeature).toHaveBeenCalledWith(123, expect.any(String));
|
|
194
|
+
});
|
|
195
|
+
it('enables gated components when hasFeature returns true', async () => {
|
|
196
|
+
mockHasFeature.mockResolvedValue(true);
|
|
197
|
+
const gatedComponent = [
|
|
198
|
+
{
|
|
199
|
+
label: 'Workflow Action Tool',
|
|
200
|
+
path: 'workflow-action-tool',
|
|
201
|
+
type: 'workflow-action',
|
|
202
|
+
cliSelector: 'workflow-action-tool',
|
|
203
|
+
supportedAuthTypes: ['oauth'],
|
|
204
|
+
supportedDistributions: ['private'],
|
|
205
|
+
},
|
|
206
|
+
];
|
|
207
|
+
const projectMetadataWithWorkflowAction = {
|
|
208
|
+
hsMetaFiles: [],
|
|
209
|
+
components: {
|
|
210
|
+
'workflow-action': { count: 0, maxCount: 3, hsMetaFiles: [] },
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
const choices = await calculateComponentTemplateChoices(gatedComponent, 'oauth', 'private', 123, projectMetadataWithWorkflowAction);
|
|
214
|
+
expect(choices).toHaveLength(1); // no disabled components
|
|
215
|
+
expect(choices[0]).toEqual({
|
|
216
|
+
name: 'Workflow Action Tool [workflow-action-tool]',
|
|
217
|
+
value: gatedComponent[0],
|
|
218
|
+
});
|
|
219
|
+
expect(mockHasFeature).toHaveBeenCalledWith(123, expect.any(String));
|
|
220
|
+
});
|
|
221
|
+
it('handles non-gated components without calling hasFeature', async () => {
|
|
222
|
+
const nonGatedComponent = [
|
|
223
|
+
{
|
|
224
|
+
label: 'Regular Component',
|
|
225
|
+
path: 'regular',
|
|
226
|
+
type: 'module',
|
|
227
|
+
supportedAuthTypes: ['oauth'],
|
|
228
|
+
supportedDistributions: ['private'],
|
|
229
|
+
},
|
|
230
|
+
];
|
|
231
|
+
const choices = await calculateComponentTemplateChoices(nonGatedComponent, 'oauth', 'private', 123, mockProjectMetadataForChoices);
|
|
232
|
+
expect(choices).toHaveLength(1);
|
|
233
|
+
expect(choices[0]).toEqual({
|
|
234
|
+
name: 'Regular Component [module]',
|
|
235
|
+
value: nonGatedComponent[0],
|
|
236
|
+
});
|
|
237
|
+
// hasFeature should not be called for non-gated components
|
|
238
|
+
expect(mockHasFeature).not.toHaveBeenCalled();
|
|
239
|
+
});
|
|
165
240
|
});
|
|
166
241
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { selectProjectTemplatePrompt, } from '../../prompts/selectProjectTemplatePrompt.js';
|
|
2
2
|
import { projectNameAndDestPrompt } from '../../prompts/projectNameAndDestPrompt.js';
|
|
3
3
|
import { DEFAULT_PROJECT_TEMPLATE_BRANCH, HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, EMPTY_PROJECT, } from '../../constants.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { isV2Project } from '../platformVersion.js';
|
|
5
|
+
import { v2ComponentFlow } from './v2.js';
|
|
6
6
|
import { getProjectTemplateListFromRepo } from './legacy.js';
|
|
7
7
|
import { uiLogger } from '../../ui/logger.js';
|
|
8
8
|
import { commands } from '../../../lang/en.js';
|
|
@@ -11,8 +11,8 @@ export async function handleProjectCreationFlow(args) {
|
|
|
11
11
|
const { platformVersion, templateSource, projectBase, auth: providedAuth, distribution: providedDistribution, } = args;
|
|
12
12
|
const repo = templateSource || HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH;
|
|
13
13
|
const projectNameAndDestPromptResponse = await projectNameAndDestPrompt(args);
|
|
14
|
-
if (
|
|
15
|
-
const { componentTemplateChoices, authType, distribution, repoConfig, projectContents, } = await
|
|
14
|
+
if (isV2Project(platformVersion)) {
|
|
15
|
+
const { componentTemplateChoices, authType, distribution, repoConfig, projectContents, } = await v2ComponentFlow(platformVersion, projectBase, providedAuth, providedDistribution, args.derivedAccountId);
|
|
16
16
|
const selectProjectTemplatePromptResponse = await selectProjectTemplatePrompt(args, undefined, projectContents !== EMPTY_PROJECT ? componentTemplateChoices : undefined);
|
|
17
17
|
return {
|
|
18
18
|
authType,
|
|
@@ -3,13 +3,13 @@ import { DEFAULT_PROJECT_TEMPLATE_BRANCH, HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH
|
|
|
3
3
|
import { EXIT_CODES } from '../../enums/exitCodes.js';
|
|
4
4
|
import { debugError } from '../../errorHandlers/index.js';
|
|
5
5
|
import { uiLogger } from '../../ui/logger.js';
|
|
6
|
-
import {
|
|
6
|
+
import { isV2Project } from '../platformVersion.js';
|
|
7
7
|
import { lib } from '../../../lang/en.js';
|
|
8
8
|
const PROJECT_TEMPLATE_PROPERTIES = ['name', 'label', 'path'];
|
|
9
9
|
export const EMPTY_PROJECT_TEMPLATE_NAME = 'no-template';
|
|
10
10
|
export async function getConfigForPlatformVersion(platformVersion) {
|
|
11
11
|
let path = '';
|
|
12
|
-
if (
|
|
12
|
+
if (isV2Project(platformVersion)) {
|
|
13
13
|
path = `${platformVersion}/`;
|
|
14
14
|
}
|
|
15
15
|
const { data } = await fetchRepoFile(HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, `${path}config.json`, DEFAULT_PROJECT_TEMPLATE_BRANCH);
|
|
@@ -2,19 +2,19 @@ import { Separator } from '@inquirer/prompts';
|
|
|
2
2
|
import { ComponentTemplate, ComponentTemplateChoice, ProjectTemplateRepoConfig } from '../../../types/Projects.js';
|
|
3
3
|
import { ProjectMetadata } from '@hubspot/project-parsing-lib/src/lib/project.js';
|
|
4
4
|
import { SelectProjectTemplatePromptResponse } from '../../prompts/selectProjectTemplatePrompt.js';
|
|
5
|
-
export declare function
|
|
5
|
+
export declare function createV2App(providedAuth: string | undefined, providedDistribution: string | undefined): Promise<{
|
|
6
6
|
authType: string;
|
|
7
7
|
distribution: string;
|
|
8
8
|
}>;
|
|
9
9
|
export declare function calculateComponentTemplateChoices(components: ComponentTemplate[], authType: string | undefined, distribution: string | undefined, accountId: number, projectMetadata?: ProjectMetadata): Promise<(ComponentTemplateChoice | Separator)[]>;
|
|
10
|
-
type
|
|
10
|
+
type V2ComponentInfo = {
|
|
11
11
|
authType?: string;
|
|
12
12
|
distribution?: string;
|
|
13
13
|
repoConfig?: ProjectTemplateRepoConfig;
|
|
14
14
|
projectContents?: string;
|
|
15
15
|
componentTemplateChoices?: (ComponentTemplateChoice | Separator)[];
|
|
16
16
|
};
|
|
17
|
-
export declare function
|
|
17
|
+
export declare function v2ComponentFlow(platformVersion: string, projectBase: string | undefined, providedAuth: string | undefined, providedDistribution: string | undefined, accountId: number): Promise<V2ComponentInfo>;
|
|
18
18
|
export declare function generateComponentPaths({ selectProjectTemplatePromptResponse, platformVersion, repoConfig, projectContents, authType, distribution, }: {
|
|
19
19
|
selectProjectTemplatePromptResponse: SelectProjectTemplatePromptResponse;
|
|
20
20
|
platformVersion: string;
|
|
@@ -3,14 +3,14 @@ import { marketplaceDistribution, oAuth, privateDistribution, staticAuth, EMPTY_
|
|
|
3
3
|
import { commands, lib } from '../../../lang/en.js';
|
|
4
4
|
import { listPrompt } from '../../prompts/promptUtils.js';
|
|
5
5
|
import chalk from 'chalk';
|
|
6
|
-
import {
|
|
6
|
+
import { isV2Project } from '../platformVersion.js';
|
|
7
7
|
import path from 'path';
|
|
8
8
|
import { getConfigForPlatformVersion } from './legacy.js';
|
|
9
9
|
import { logError } from '../../errorHandlers/index.js';
|
|
10
10
|
import { EXIT_CODES } from '../../enums/exitCodes.js';
|
|
11
11
|
import { hasFeature } from '../../hasFeature.js';
|
|
12
12
|
import { AppEventsKey, PagesKey, } from '@hubspot/project-parsing-lib/src/lib/constants.js';
|
|
13
|
-
export async function
|
|
13
|
+
export async function createV2App(providedAuth, providedDistribution) {
|
|
14
14
|
let authType;
|
|
15
15
|
if (providedAuth &&
|
|
16
16
|
providedDistribution === marketplaceDistribution &&
|
|
@@ -52,6 +52,7 @@ export async function createV3App(providedAuth, providedDistribution) {
|
|
|
52
52
|
const componentTypeToGateMap = {
|
|
53
53
|
[AppEventsKey]: FEATURES.APP_EVENTS,
|
|
54
54
|
[PagesKey]: FEATURES.APPS_HOME,
|
|
55
|
+
'workflow-action-tool': FEATURES.AGENT_TOOLS,
|
|
55
56
|
};
|
|
56
57
|
export async function calculateComponentTemplateChoices(components, authType, distribution, accountId, projectMetadata) {
|
|
57
58
|
const enabledComponents = [];
|
|
@@ -73,18 +74,19 @@ export async function calculateComponentTemplateChoices(components, authType, di
|
|
|
73
74
|
}
|
|
74
75
|
if (Array.isArray(supportedAuthTypes) &&
|
|
75
76
|
authType &&
|
|
76
|
-
!supportedAuthTypes.includes(authType)) {
|
|
77
|
+
!supportedAuthTypes.includes(authType.toLowerCase())) {
|
|
77
78
|
disabledReasons.push(commands.project.add.error.authTypeNotAllowed(authType));
|
|
78
79
|
}
|
|
79
80
|
if (Array.isArray(supportedDistributions) &&
|
|
80
81
|
distribution &&
|
|
81
|
-
!supportedDistributions.includes(distribution)) {
|
|
82
|
+
!supportedDistributions.includes(distribution.toLowerCase())) {
|
|
82
83
|
disabledReasons.push(commands.project.add.error.distributionNotAllowed(distribution));
|
|
83
84
|
}
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
const templateGate = componentTypeToGateMap[template.cliSelector || template.type];
|
|
86
|
+
if (templateGate) {
|
|
87
|
+
const isUngated = await hasFeature(accountId, templateGate);
|
|
86
88
|
if (!isUngated) {
|
|
87
|
-
disabledReasons.
|
|
89
|
+
disabledReasons.unshift(commands.project.add.error.portalDoesNotHaveAccessToThisFeature(accountId));
|
|
88
90
|
}
|
|
89
91
|
}
|
|
90
92
|
if (disabledReasons.length > 0) {
|
|
@@ -96,7 +98,7 @@ export async function calculateComponentTemplateChoices(components, authType, di
|
|
|
96
98
|
}
|
|
97
99
|
else {
|
|
98
100
|
enabledComponents.push({
|
|
99
|
-
name: template.label
|
|
101
|
+
name: `${template.label} [${template.cliSelector || template.type}]`,
|
|
100
102
|
value: template,
|
|
101
103
|
});
|
|
102
104
|
}
|
|
@@ -110,7 +112,7 @@ export async function calculateComponentTemplateChoices(components, authType, di
|
|
|
110
112
|
]
|
|
111
113
|
: [...enabledComponents];
|
|
112
114
|
}
|
|
113
|
-
export async function
|
|
115
|
+
export async function v2ComponentFlow(platformVersion, projectBase, providedAuth, providedDistribution, accountId) {
|
|
114
116
|
let repoConfig = undefined;
|
|
115
117
|
let authType;
|
|
116
118
|
let distribution;
|
|
@@ -132,7 +134,7 @@ export async function v3ComponentFlow(platformVersion, projectBase, providedAuth
|
|
|
132
134
|
],
|
|
133
135
|
}));
|
|
134
136
|
if (projectContentsChoice === PROJECT_WITH_APP) {
|
|
135
|
-
const { authType: selectedAuthType, distribution: selectedDistribution } = await
|
|
137
|
+
const { authType: selectedAuthType, distribution: selectedDistribution } = await createV2App(providedAuth, providedDistribution);
|
|
136
138
|
authType = selectedAuthType;
|
|
137
139
|
distribution = selectedDistribution;
|
|
138
140
|
}
|
|
@@ -146,7 +148,7 @@ export async function v3ComponentFlow(platformVersion, projectBase, providedAuth
|
|
|
146
148
|
};
|
|
147
149
|
}
|
|
148
150
|
export function generateComponentPaths({ selectProjectTemplatePromptResponse, platformVersion, repoConfig, projectContents, authType, distribution, }) {
|
|
149
|
-
if (!
|
|
151
|
+
if (!isV2Project(platformVersion)) {
|
|
150
152
|
return [];
|
|
151
153
|
}
|
|
152
154
|
const components = selectProjectTemplatePromptResponse.componentTemplates?.map((componentTemplate) => {
|
package/lib/projects/deploy.d.ts
CHANGED
|
@@ -10,4 +10,4 @@ export declare function logDeployErrors(errorData: {
|
|
|
10
10
|
};
|
|
11
11
|
}>;
|
|
12
12
|
}): void;
|
|
13
|
-
export declare function handleProjectDeploy(targetAccountId: number, projectName: string, buildId: number,
|
|
13
|
+
export declare function handleProjectDeploy(targetAccountId: number, projectName: string, buildId: number, isV2Project: boolean, force: boolean): Promise<Deploy | undefined>;
|