@hubspot/cli 8.0.10-experimental.3 → 8.0.10-experimental.5
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/api/migrate.js +5 -1
- package/commands/app/__tests__/migrate.test.js +2 -2
- package/commands/app/migrate.js +3 -3
- package/commands/cms/__tests__/upload.test.js +4 -0
- package/commands/project/__tests__/create.test.js +2 -2
- package/commands/project/__tests__/migrate.test.js +3 -3
- package/commands/project/create.js +3 -3
- package/commands/project/migrate.js +7 -7
- package/lang/en.d.ts +2 -3
- package/lang/en.js +2 -3
- package/lib/app/__tests__/migrate.test.js +1 -1
- package/lib/app/migrate.js +1 -1
- package/lib/theme/__tests__/migrate.test.js +7 -16
- package/lib/theme/migrate.d.ts +1 -1
- package/lib/theme/migrate.js +1 -5
- package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +1 -0
- package/mcp-server/tools/project/CreateProjectTool.d.ts +1 -0
- package/mcp-server/tools/project/CreateProjectTool.js +2 -1
- package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +0 -1
- package/mcp-server/tools/project/constants.d.ts +1 -0
- package/mcp-server/tools/project/constants.js +2 -1
- package/package.json +3 -3
package/api/migrate.js
CHANGED
|
@@ -23,7 +23,11 @@ function mapPlatformVersionToEnum(platformVersion) {
|
|
|
23
23
|
if (platformVersion === PLATFORM_VERSIONS.unstable) {
|
|
24
24
|
return PLATFORM_VERSIONS.unstable.toUpperCase();
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
const reformattedPlatformVersion = platformVersion
|
|
27
|
+
.replaceAll('.', '_')
|
|
28
|
+
.replaceAll('-', '_')
|
|
29
|
+
.toUpperCase();
|
|
30
|
+
return `V${reformattedPlatformVersion}`;
|
|
27
31
|
}
|
|
28
32
|
export async function initializeAppMigration(accountId, applicationId, platformVersion) {
|
|
29
33
|
return http.post(accountId, {
|
|
@@ -89,7 +89,7 @@ describe('commands/app/migrate', () => {
|
|
|
89
89
|
}),
|
|
90
90
|
'platform-version': expect.objectContaining({
|
|
91
91
|
type: 'string',
|
|
92
|
-
default: '
|
|
92
|
+
default: '2026.03',
|
|
93
93
|
}),
|
|
94
94
|
}));
|
|
95
95
|
});
|
|
@@ -97,7 +97,7 @@ describe('commands/app/migrate', () => {
|
|
|
97
97
|
await migrateCommand.builder(mockYargs);
|
|
98
98
|
expect(optionsSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
99
99
|
'platform-version': expect.objectContaining({
|
|
100
|
-
default: '
|
|
100
|
+
default: '2026.03',
|
|
101
101
|
}),
|
|
102
102
|
}));
|
|
103
103
|
});
|
package/commands/app/migrate.js
CHANGED
|
@@ -8,7 +8,7 @@ import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
|
8
8
|
import { migrateApp } from '../../lib/app/migrate.js';
|
|
9
9
|
import { getIsInProject } from '../../lib/projects/config.js';
|
|
10
10
|
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
11
|
-
const { v2025_2 } = PLATFORM_VERSIONS;
|
|
11
|
+
const { v2025_2, v2026_03_beta, v2026_03 } = PLATFORM_VERSIONS;
|
|
12
12
|
const command = 'migrate';
|
|
13
13
|
const describe = commands.project.migrateApp.describe;
|
|
14
14
|
export function handlerGenerator(commandTrackingName) {
|
|
@@ -67,8 +67,8 @@ function appMigrateBuilder(yargs) {
|
|
|
67
67
|
},
|
|
68
68
|
'platform-version': {
|
|
69
69
|
type: 'string',
|
|
70
|
-
choices: [v2025_2],
|
|
71
|
-
default:
|
|
70
|
+
choices: [v2025_2, v2026_03_beta, v2026_03],
|
|
71
|
+
default: v2026_03,
|
|
72
72
|
},
|
|
73
73
|
unstable: {
|
|
74
74
|
type: 'boolean',
|
|
@@ -8,6 +8,7 @@ import * as modulesLib from '@hubspot/local-dev-lib/cms/modules';
|
|
|
8
8
|
import * as ignoreRulesLib from '@hubspot/local-dev-lib/ignoreRules';
|
|
9
9
|
import * as themesLib from '@hubspot/local-dev-lib/cms/themes';
|
|
10
10
|
import * as configLib from '@hubspot/local-dev-lib/config';
|
|
11
|
+
import * as handleFieldsJSLib from '@hubspot/local-dev-lib/cms/handleFieldsJS';
|
|
11
12
|
import { uiLogger } from '../../../lib/ui/logger.js';
|
|
12
13
|
import * as errorHandlers from '../../../lib/errorHandlers/index.js';
|
|
13
14
|
import * as commonOpts from '../../../lib/commonOpts.js';
|
|
@@ -26,6 +27,7 @@ vi.mock('@hubspot/local-dev-lib/cms/modules');
|
|
|
26
27
|
vi.mock('@hubspot/local-dev-lib/ignoreRules');
|
|
27
28
|
vi.mock('@hubspot/local-dev-lib/cms/themes');
|
|
28
29
|
vi.mock('@hubspot/local-dev-lib/config');
|
|
30
|
+
vi.mock('@hubspot/local-dev-lib/cms/handleFieldsJS');
|
|
29
31
|
vi.mock('../../../lib/errorHandlers/index.js');
|
|
30
32
|
vi.mock('../../../lib/commonOpts.js');
|
|
31
33
|
vi.mock('../../../lib/prompts/uploadPrompt.js');
|
|
@@ -53,6 +55,7 @@ const hasUploadErrorsSpy = vi.spyOn(uploadFolderLib, 'hasUploadErrors');
|
|
|
53
55
|
const processExitSpy = vi.spyOn(process, 'exit');
|
|
54
56
|
const logErrorSpy = vi.spyOn(errorHandlers, 'logError');
|
|
55
57
|
const getConfigAccountIfExistsSpy = vi.spyOn(configLib, 'getConfigAccountIfExists');
|
|
58
|
+
const isConvertableFieldJsSpy = vi.spyOn(handleFieldsJSLib, 'isConvertableFieldJs');
|
|
56
59
|
describe('commands/cms/upload', () => {
|
|
57
60
|
beforeEach(() => {
|
|
58
61
|
// @ts-expect-error Mock implementation
|
|
@@ -67,6 +70,7 @@ describe('commands/cms/upload', () => {
|
|
|
67
70
|
getThemePreviewUrlSpy.mockReturnValue(undefined);
|
|
68
71
|
// Mock config to prevent reading actual config file in CI
|
|
69
72
|
getConfigAccountIfExistsSpy.mockReturnValue(undefined);
|
|
73
|
+
isConvertableFieldJsSpy.mockReturnValue(false);
|
|
70
74
|
});
|
|
71
75
|
describe('command', () => {
|
|
72
76
|
it('should have the correct command structure', () => {
|
|
@@ -50,8 +50,8 @@ describe('commands/project/create', () => {
|
|
|
50
50
|
expect(optionsCall['platform-version']).toEqual(expect.objectContaining({
|
|
51
51
|
describe: 'The target platform version for the new project.',
|
|
52
52
|
type: 'string',
|
|
53
|
-
choices: ['2025.1', '2025.2', '2026.03-beta'],
|
|
54
|
-
default: '
|
|
53
|
+
choices: ['2025.1', '2025.2', '2026.03-beta', '2026.03'],
|
|
54
|
+
default: '2026.03',
|
|
55
55
|
}));
|
|
56
56
|
});
|
|
57
57
|
it('should define project base option with correct choices', () => {
|
|
@@ -9,7 +9,7 @@ import { uiBetaTag, uiCommandReference } from '../../../lib/ui/index.js';
|
|
|
9
9
|
vi.mock('../../../lib/app/migrate');
|
|
10
10
|
vi.mock('../../../lib/projects/config');
|
|
11
11
|
vi.mock('../../../lib/ui');
|
|
12
|
-
const { v2025_2 } = PLATFORM_VERSIONS;
|
|
12
|
+
const { v2025_2, v2026_03_beta, v2026_03 } = PLATFORM_VERSIONS;
|
|
13
13
|
describe('commands/project/migrate', () => {
|
|
14
14
|
const yargsMock = yargs;
|
|
15
15
|
const optionsSpy = vi.spyOn(yargsMock, 'option').mockReturnValue(yargsMock);
|
|
@@ -48,8 +48,8 @@ describe('commands/project/migrate', () => {
|
|
|
48
48
|
migrateCommand.builder(yargsMock);
|
|
49
49
|
expect(optionsSpy).toHaveBeenCalledWith('platform-version', {
|
|
50
50
|
type: 'string',
|
|
51
|
-
choices: [v2025_2],
|
|
52
|
-
default:
|
|
51
|
+
choices: [v2025_2, v2026_03_beta, v2026_03],
|
|
52
|
+
default: v2026_03,
|
|
53
53
|
});
|
|
54
54
|
expect(optionsSpy).toHaveBeenCalledWith('unstable', {
|
|
55
55
|
type: 'boolean',
|
|
@@ -20,7 +20,7 @@ import { updateHsMetaFilesWithAutoGeneratedFields } from '../../lib/projects/com
|
|
|
20
20
|
import SpinniesManager from '../../lib/ui/SpinniesManager.js';
|
|
21
21
|
const command = ['create', 'init'];
|
|
22
22
|
const describe = commands.project.create.describe;
|
|
23
|
-
const { v2025_1, v2025_2, v2026_03_beta } = PLATFORM_VERSIONS;
|
|
23
|
+
const { v2025_1, v2025_2, v2026_03_beta, v2026_03 } = PLATFORM_VERSIONS;
|
|
24
24
|
async function handler(args) {
|
|
25
25
|
const { derivedAccountId, platformVersion, templateSource } = args;
|
|
26
26
|
if (templateSource && !templateSource.includes('/')) {
|
|
@@ -125,8 +125,8 @@ function projectCreateBuilder(yargs) {
|
|
|
125
125
|
'platform-version': {
|
|
126
126
|
describe: commands.project.create.options.platformVersion.describe,
|
|
127
127
|
type: 'string',
|
|
128
|
-
choices: [v2025_1, v2025_2, v2026_03_beta],
|
|
129
|
-
default:
|
|
128
|
+
choices: [v2025_1, v2025_2, v2026_03_beta, v2026_03],
|
|
129
|
+
default: v2026_03,
|
|
130
130
|
},
|
|
131
131
|
'project-base': {
|
|
132
132
|
describe: commands.project.create.options.projectBase.describe,
|
|
@@ -9,11 +9,11 @@ import { commands, lib } from '../../lang/en.js';
|
|
|
9
9
|
import { uiLogger } from '../../lib/ui/logger.js';
|
|
10
10
|
import { renderInline } from '../../ui/render.js';
|
|
11
11
|
import { getWarningBox } from '../../ui/components/StatusMessageBoxes.js';
|
|
12
|
-
import { getHasMigratableThemes,
|
|
12
|
+
import { getHasMigratableThemes, migrateThemesV2, } from '../../lib/theme/migrate.js';
|
|
13
13
|
import { hasFeature } from '../../lib/hasFeature.js';
|
|
14
14
|
import { FEATURES } from '../../lib/constants.js';
|
|
15
15
|
import { trackCommandMetadataUsage, trackCommandUsage, } from '../../lib/usageTracking.js';
|
|
16
|
-
const { v2025_2 } = PLATFORM_VERSIONS;
|
|
16
|
+
const { v2025_2, v2026_03_beta, v2026_03 } = PLATFORM_VERSIONS;
|
|
17
17
|
const command = 'migrate';
|
|
18
18
|
const describe = commands.project.migrate.describe;
|
|
19
19
|
async function handler(args) {
|
|
@@ -26,8 +26,8 @@ async function handler(args) {
|
|
|
26
26
|
}
|
|
27
27
|
if (projectConfig?.projectConfig) {
|
|
28
28
|
await renderInline(getWarningBox({
|
|
29
|
-
title: lib.migrate.projectMigrationWarningTitle,
|
|
30
|
-
message: lib.migrate.projectMigrationWarning,
|
|
29
|
+
title: lib.migrate.projectMigrationWarningTitle(platformVersion),
|
|
30
|
+
message: lib.migrate.projectMigrationWarning(platformVersion),
|
|
31
31
|
}));
|
|
32
32
|
}
|
|
33
33
|
try {
|
|
@@ -38,7 +38,7 @@ async function handler(args) {
|
|
|
38
38
|
uiLogger.error(commands.project.migrate.errors.noThemeMigrationAccess(derivedAccountId));
|
|
39
39
|
return process.exit(EXIT_CODES.ERROR);
|
|
40
40
|
}
|
|
41
|
-
await
|
|
41
|
+
await migrateThemesV2(derivedAccountId, {
|
|
42
42
|
...args,
|
|
43
43
|
platformVersion: unstable
|
|
44
44
|
? PLATFORM_VERSIONS.unstable
|
|
@@ -67,8 +67,8 @@ function projectMigrateBuilder(yargs) {
|
|
|
67
67
|
yargs
|
|
68
68
|
.option('platform-version', {
|
|
69
69
|
type: 'string',
|
|
70
|
-
choices: [v2025_2],
|
|
71
|
-
default:
|
|
70
|
+
choices: [v2025_2, v2026_03_beta, v2026_03],
|
|
71
|
+
default: v2026_03,
|
|
72
72
|
})
|
|
73
73
|
.option('unstable', {
|
|
74
74
|
type: 'boolean',
|
package/lang/en.d.ts
CHANGED
|
@@ -1494,7 +1494,6 @@ export declare const commands: {
|
|
|
1494
1494
|
};
|
|
1495
1495
|
};
|
|
1496
1496
|
header: string;
|
|
1497
|
-
deprecationWarning: (platformVersion: string) => string;
|
|
1498
1497
|
migrationStatus: {
|
|
1499
1498
|
inProgress: () => string;
|
|
1500
1499
|
success: () => string;
|
|
@@ -3920,8 +3919,8 @@ export declare const lib: {
|
|
|
3920
3919
|
componentsToBeMigrated: (components: string) => string;
|
|
3921
3920
|
componentsThatWillNotBeMigrated: (components: string) => string;
|
|
3922
3921
|
sourceContentsMoved: (newLocation: string) => string;
|
|
3923
|
-
projectMigrationWarningTitle: string;
|
|
3924
|
-
projectMigrationWarning: string;
|
|
3922
|
+
projectMigrationWarningTitle: (platformVersion: string) => string;
|
|
3923
|
+
projectMigrationWarning: (platformVersion: string) => string;
|
|
3925
3924
|
exitWithoutMigrating: string;
|
|
3926
3925
|
success: {
|
|
3927
3926
|
downloadedProject: (projectName: string, projectDest: string) => string;
|
package/lang/en.js
CHANGED
|
@@ -1510,7 +1510,6 @@ export const commands = {
|
|
|
1510
1510
|
},
|
|
1511
1511
|
},
|
|
1512
1512
|
header: `This command will migrate an app to the projects framework. It will walk you through the fields required to complete the migration and download the project source code into a directory of your choosing.\n${uiLink('Learn more about migrating apps to the projects framework', 'https://developers.hubspot.com/docs/platform/migrate-a-public-app-to-projects')}`,
|
|
1513
|
-
deprecationWarning: (platformVersion) => `The ${uiCommandReference('hs project migrate-app')} command is deprecated and will be removed. Use ${uiCommandReference(`hs app migrate --platform-version=${platformVersion}`)} going forward.`,
|
|
1514
1513
|
migrationStatus: {
|
|
1515
1514
|
inProgress: () => `Converting app configuration to ${chalk.bold(LEGACY_PUBLIC_APP_FILE)} component definition ...`,
|
|
1516
1515
|
success: () => `${chalk.bold('Your app was converted and build #1 is deployed')}`,
|
|
@@ -3943,8 +3942,8 @@ export const lib = {
|
|
|
3943
3942
|
componentsToBeMigrated: (components) => `The following features will be migrated: ${components}`,
|
|
3944
3943
|
componentsThatWillNotBeMigrated: (components) => `[NOTE] These features are not yet supported for migration but will be available later: ${components}`,
|
|
3945
3944
|
sourceContentsMoved: (newLocation) => `The contents of your old source directory have been moved to ${newLocation}, move any required files to the new source directory.`,
|
|
3946
|
-
projectMigrationWarningTitle:
|
|
3947
|
-
projectMigrationWarning: uiBetaTag(`Running the ${uiCommandReference('hs project migrate')} command will permanently upgrade your project to platformVersion
|
|
3945
|
+
projectMigrationWarningTitle: (platformVersion) => `Important: Migrating to platformVersion ${platformVersion} is irreversible`,
|
|
3946
|
+
projectMigrationWarning: (platformVersion) => uiBetaTag(`Running the ${uiCommandReference('hs project migrate')} command will permanently upgrade your project to platformVersion ${platformVersion}. This action cannot be undone. To ensure you have access to your original files, they will be copied to a new directory (archive) for safekeeping.\n\nThis command will guide you through the process, prompting you to enter the required fields and will download the new project source code into your project source directory.`, false),
|
|
3948
3947
|
exitWithoutMigrating: 'Exiting without migrating',
|
|
3949
3948
|
success: {
|
|
3950
3949
|
downloadedProject: (projectName, projectDest) => `Saved ${projectName} to ${projectDest}`,
|
|
@@ -424,7 +424,7 @@ describe('lib/app/migrate', () => {
|
|
|
424
424
|
};
|
|
425
425
|
mockedPoll.mockResolvedValue(mockStatus);
|
|
426
426
|
const result = await pollMigrationStatus(ACCOUNT_ID, MIGRATION_ID);
|
|
427
|
-
expect(mockedPoll).toHaveBeenCalledWith(expect.any(Function), expect.any(Object));
|
|
427
|
+
expect(mockedPoll).toHaveBeenCalledWith(expect.any(Function), expect.any(Object), 300_000);
|
|
428
428
|
expect(result).toBe(mockStatus);
|
|
429
429
|
});
|
|
430
430
|
});
|
package/lib/app/migrate.js
CHANGED
|
@@ -255,7 +255,7 @@ export async function pollMigrationStatus(derivedAccountId, migrationId, success
|
|
|
255
255
|
return poll(() => checkMigrationStatusV2(derivedAccountId, migrationId), {
|
|
256
256
|
successStates: [...successStates],
|
|
257
257
|
errorStates: [...DEFAULT_POLLING_STATUS_LOOKUP.errorStates],
|
|
258
|
-
});
|
|
258
|
+
}, 300_000);
|
|
259
259
|
}
|
|
260
260
|
export async function finalizeAppMigration(derivedAccountId, migrationId, uidMap, projectName) {
|
|
261
261
|
let pollResponse;
|
|
@@ -3,15 +3,13 @@ import { getConfigAccountById } from '@hubspot/local-dev-lib/config';
|
|
|
3
3
|
import { confirmPrompt } from '../../prompts/promptUtils.js';
|
|
4
4
|
import { writeProjectConfig, } from '../../projects/config.js';
|
|
5
5
|
import { ensureProjectExists } from '../../projects/ensureProjectExists.js';
|
|
6
|
-
import { isV2Project } from '../../projects/platformVersion.js';
|
|
7
6
|
import { fetchMigrationApps } from '../../app/migrate.js';
|
|
8
|
-
import { getHasMigratableThemes, validateMigrationAppsAndThemes, handleThemesMigration,
|
|
7
|
+
import { getHasMigratableThemes, validateMigrationAppsAndThemes, handleThemesMigration, migrateThemesV2, } from '../migrate.js';
|
|
9
8
|
import { lib } from '../../../lang/en.js';
|
|
10
9
|
vi.mock('@hubspot/project-parsing-lib/themes');
|
|
11
10
|
vi.mock('../../prompts/promptUtils');
|
|
12
11
|
vi.mock('../../projects/config');
|
|
13
12
|
vi.mock('../../projects/ensureProjectExists');
|
|
14
|
-
vi.mock('../../projects/platformVersion');
|
|
15
13
|
vi.mock('../../app/migrate');
|
|
16
14
|
vi.mock('@hubspot/local-dev-lib/config');
|
|
17
15
|
vi.mock('../../ui/SpinniesManager', () => ({
|
|
@@ -28,7 +26,6 @@ const mockedMigrateThemes = migrateThemes;
|
|
|
28
26
|
const mockedConfirmPrompt = confirmPrompt;
|
|
29
27
|
const mockedWriteProjectConfig = writeProjectConfig;
|
|
30
28
|
const mockedEnsureProjectExists = ensureProjectExists;
|
|
31
|
-
const mockedUseV2Api = isV2Project;
|
|
32
29
|
const mockedFetchMigrationApps = fetchMigrationApps;
|
|
33
30
|
const mockedGetConfigAccountById = getConfigAccountById;
|
|
34
31
|
const ACCOUNT_ID = 123;
|
|
@@ -41,7 +38,6 @@ const createLoadedProjectConfig = (name) => ({
|
|
|
41
38
|
});
|
|
42
39
|
describe('lib/theme/migrate', () => {
|
|
43
40
|
beforeEach(() => {
|
|
44
|
-
mockedUseV2Api.mockReturnValue(false);
|
|
45
41
|
// Mock account config for the test account ID
|
|
46
42
|
mockedGetConfigAccountById.mockReturnValue({
|
|
47
43
|
accountId: ACCOUNT_ID,
|
|
@@ -144,11 +140,6 @@ describe('lib/theme/migrate', () => {
|
|
|
144
140
|
});
|
|
145
141
|
});
|
|
146
142
|
describe('validateMigrationAppsAndThemes', () => {
|
|
147
|
-
it('should throw an error when themes are already migrated (v2 API)', async () => {
|
|
148
|
-
mockedUseV2Api.mockReturnValue(true);
|
|
149
|
-
const projectConfig = createLoadedProjectConfig(PROJECT_NAME);
|
|
150
|
-
await expect(validateMigrationAppsAndThemes(0, projectConfig)).rejects.toThrow(lib.migrate.errors.project.themesAlreadyMigrated);
|
|
151
|
-
});
|
|
152
143
|
it('should throw an error when apps and themes are both present', async () => {
|
|
153
144
|
const projectConfig = createLoadedProjectConfig(PROJECT_NAME);
|
|
154
145
|
await expect(validateMigrationAppsAndThemes(1, projectConfig)).rejects.toThrow(lib.migrate.errors.project.themesAndAppsNotAllowed);
|
|
@@ -204,7 +195,7 @@ describe('lib/theme/migrate', () => {
|
|
|
204
195
|
await expect(handleThemesMigration(projectConfig, PLATFORM_VERSION)).rejects.toThrow(lib.migrate.errors.project.failedToMigrateThemes);
|
|
205
196
|
});
|
|
206
197
|
});
|
|
207
|
-
describe('
|
|
198
|
+
describe('migrateThemesV2', () => {
|
|
208
199
|
const options = {
|
|
209
200
|
platformVersion: PLATFORM_VERSION,
|
|
210
201
|
};
|
|
@@ -230,25 +221,25 @@ describe('lib/theme/migrate', () => {
|
|
|
230
221
|
projectConfig: undefined,
|
|
231
222
|
projectDir: MOCK_PROJECT_DIR,
|
|
232
223
|
};
|
|
233
|
-
await expect(
|
|
224
|
+
await expect(migrateThemesV2(ACCOUNT_ID, options, themeCount, invalidProjectConfig)).rejects.toThrow(lib.migrate.errors.project.invalidConfig);
|
|
234
225
|
});
|
|
235
226
|
it('should throw an error when project does not exist', async () => {
|
|
236
227
|
mockedEnsureProjectExists.mockResolvedValue({ projectExists: false });
|
|
237
|
-
await expect(
|
|
228
|
+
await expect(migrateThemesV2(ACCOUNT_ID, options, themeCount, projectConfig)).rejects.toThrow(lib.migrate.errors.project.doesNotExist(ACCOUNT_ID));
|
|
238
229
|
});
|
|
239
230
|
it('should proceed with migration when user confirms', async () => {
|
|
240
|
-
await
|
|
231
|
+
await migrateThemesV2(ACCOUNT_ID, options, themeCount, projectConfig);
|
|
241
232
|
expect(mockedFetchMigrationApps).toHaveBeenCalledWith(ACCOUNT_ID, PLATFORM_VERSION, { projectConfig });
|
|
242
233
|
expect(mockedConfirmPrompt).toHaveBeenCalledWith(lib.migrate.prompt.proceed, { defaultAnswer: false });
|
|
243
234
|
expect(mockedMigrateThemes).toHaveBeenCalledWith(MOCK_PROJECT_DIR, `${MOCK_PROJECT_DIR}/src`);
|
|
244
235
|
});
|
|
245
236
|
it('should exit without migrating when user cancels', async () => {
|
|
246
237
|
mockedConfirmPrompt.mockResolvedValue(false);
|
|
247
|
-
await
|
|
238
|
+
await migrateThemesV2(ACCOUNT_ID, options, themeCount, projectConfig);
|
|
248
239
|
expect(mockedMigrateThemes).not.toHaveBeenCalled();
|
|
249
240
|
});
|
|
250
241
|
it('should validate migration apps and themes', async () => {
|
|
251
|
-
await
|
|
242
|
+
await migrateThemesV2(ACCOUNT_ID, options, themeCount, projectConfig);
|
|
252
243
|
// The validation is called internally, so we verify it through the error handling
|
|
253
244
|
expect(mockedFetchMigrationApps).toHaveBeenCalled();
|
|
254
245
|
});
|
package/lib/theme/migrate.d.ts
CHANGED
|
@@ -10,4 +10,4 @@ export declare function getHasMigratableThemes(projectConfig?: LoadedProjectConf
|
|
|
10
10
|
}>;
|
|
11
11
|
export declare function validateMigrationAppsAndThemes(hasApps: number, projectConfig?: LoadedProjectConfig): Promise<void>;
|
|
12
12
|
export declare function handleThemesMigration(projectConfig: LoadedProjectConfig, platformVersion: string): Promise<void>;
|
|
13
|
-
export declare function
|
|
13
|
+
export declare function migrateThemesV2(derivedAccountId: number, options: ArgumentsCamelCase<MigrateThemesArgs>, themeCount: number, projectConfig: LoadedProjectConfig): Promise<void>;
|
package/lib/theme/migrate.js
CHANGED
|
@@ -7,7 +7,6 @@ import { lib } from '../../lang/en.js';
|
|
|
7
7
|
import { PROJECT_CONFIG_FILE } from '../constants.js';
|
|
8
8
|
import { uiLogger } from '../ui/logger.js';
|
|
9
9
|
import { debugError } from '../errorHandlers/index.js';
|
|
10
|
-
import { isV2Project } from '../projects/platformVersion.js';
|
|
11
10
|
import { confirmPrompt } from '../prompts/promptUtils.js';
|
|
12
11
|
import { fetchMigrationApps } from '../app/migrate.js';
|
|
13
12
|
export async function getHasMigratableThemes(projectConfig) {
|
|
@@ -22,9 +21,6 @@ export async function getHasMigratableThemes(projectConfig) {
|
|
|
22
21
|
};
|
|
23
22
|
}
|
|
24
23
|
export async function validateMigrationAppsAndThemes(hasApps, projectConfig) {
|
|
25
|
-
if (isV2Project(projectConfig?.projectConfig?.platformVersion)) {
|
|
26
|
-
throw new Error(lib.migrate.errors.project.themesAlreadyMigrated);
|
|
27
|
-
}
|
|
28
24
|
if (hasApps > 0 && projectConfig) {
|
|
29
25
|
throw new Error(lib.migrate.errors.project.themesAndAppsNotAllowed);
|
|
30
26
|
}
|
|
@@ -61,7 +57,7 @@ export async function handleThemesMigration(projectConfig, platformVersion) {
|
|
|
61
57
|
uiLogger.log('');
|
|
62
58
|
uiLogger.log(lib.migrate.success.themesMigrationSuccess(platformVersion));
|
|
63
59
|
}
|
|
64
|
-
export async function
|
|
60
|
+
export async function migrateThemesV2(derivedAccountId, options, themeCount, projectConfig) {
|
|
65
61
|
if (!projectConfig?.projectConfig || !projectConfig?.projectDir) {
|
|
66
62
|
throw new Error(lib.migrate.errors.project.invalidConfig);
|
|
67
63
|
}
|
|
@@ -8,6 +8,7 @@ import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
|
8
8
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
9
9
|
import { setupHubSpotConfig } from '../../utils/config.js';
|
|
10
10
|
import { getErrorMessage } from '../../../lib/errorHandlers/index.js';
|
|
11
|
+
import { PLATFORM_VERSIONS } from '@hubspot/local-dev-lib/constants/projects';
|
|
11
12
|
const inputSchema = {
|
|
12
13
|
absoluteCurrentWorkingDirectory,
|
|
13
14
|
name: z
|
|
@@ -40,7 +41,7 @@ export class CreateProjectTool extends Tool {
|
|
|
40
41
|
async handler({ name, destination, projectBase, distribution, auth, features, absoluteCurrentWorkingDirectory, }) {
|
|
41
42
|
setupHubSpotConfig(absoluteCurrentWorkingDirectory);
|
|
42
43
|
await trackToolUsage(toolName);
|
|
43
|
-
let command = addFlag('hs project create', 'platform-version',
|
|
44
|
+
let command = addFlag('hs project create', 'platform-version', PLATFORM_VERSIONS.v2026_03);
|
|
44
45
|
const content = [];
|
|
45
46
|
if (name) {
|
|
46
47
|
command = addFlag(command, 'name', name);
|
|
@@ -55,7 +55,6 @@ describe('mcp-server/tools/project/CreateProjectTool', () => {
|
|
|
55
55
|
stderr: '',
|
|
56
56
|
});
|
|
57
57
|
const result = await tool.handler(baseInput);
|
|
58
|
-
expect(mockAddFlag).toHaveBeenCalledWith('hs project create', 'platform-version', '2025.2');
|
|
59
58
|
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'name', 'test-project');
|
|
60
59
|
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'dest', './test-dest');
|
|
61
60
|
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'project-base', EMPTY_PROJECT);
|
|
@@ -10,6 +10,7 @@ export declare const features: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
|
10
10
|
webhooks: "webhooks";
|
|
11
11
|
"workflow-action": "workflow-action";
|
|
12
12
|
"app-function": "app-function";
|
|
13
|
+
"app-function-endpoint": "app-function-endpoint";
|
|
13
14
|
"app-object": "app-object";
|
|
14
15
|
scim: "scim";
|
|
15
16
|
}>>>;
|
|
@@ -10,6 +10,7 @@ export const features = z
|
|
|
10
10
|
'card',
|
|
11
11
|
'settings',
|
|
12
12
|
'app-function',
|
|
13
|
+
'app-function-endpoint',
|
|
13
14
|
'webhooks',
|
|
14
15
|
'workflow-action',
|
|
15
16
|
'workflow-action-tool',
|
|
@@ -18,7 +19,7 @@ export const features = z
|
|
|
18
19
|
'scim',
|
|
19
20
|
'page',
|
|
20
21
|
]))
|
|
21
|
-
.describe('The features to include in the project, multiple options can be selected. "app-function" is also known as a
|
|
22
|
+
.describe('The features to include in the project, multiple options can be selected. "app-function" is also known as a private serverless function. "app-function-endpoint" is a serverless functions that is publicly accessible via endpoint. "workflow-action" is also known as a custom workflow action. "workflow-action-tool" is also known as agent tools.')
|
|
22
23
|
.optional();
|
|
23
24
|
export const docsSearchQuery = z
|
|
24
25
|
.string()
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "8.0.10-experimental.
|
|
3
|
+
"version": "8.0.10-experimental.5",
|
|
4
4
|
"description": "The official CLI for developing on HubSpot",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": "https://github.com/HubSpot/hubspot-cli",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@hubspot/local-dev-lib": "5.
|
|
10
|
-
"@hubspot/project-parsing-lib": "0.
|
|
9
|
+
"@hubspot/local-dev-lib": "5.2.0",
|
|
10
|
+
"@hubspot/project-parsing-lib": "0.12.1",
|
|
11
11
|
"@hubspot/serverless-dev-runtime": "7.0.7",
|
|
12
12
|
"@hubspot/ui-extensions-dev-server": "2.0.0",
|
|
13
13
|
"@inquirer/prompts": "7.1.0",
|