@hubspot/cli 7.4.2-experimental.0 → 7.4.4-experimental.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,61 @@
1
+ import { HubSpotPromise } from '@hubspot/local-dev-lib/types/Http';
2
+ import { UNMIGRATABLE_REASONS } from '@hubspot/local-dev-lib/constants/projects';
3
+ import { MIGRATION_STATUS } from '@hubspot/local-dev-lib/types/Migration';
4
+ interface BaseMigrationApp {
5
+ appId: number;
6
+ appName: string;
7
+ isMigratable: boolean;
8
+ migrationComponents: ListAppsMigrationComponent[];
9
+ projectName?: string;
10
+ }
11
+ export interface MigratableApp extends BaseMigrationApp {
12
+ isMigratable: true;
13
+ }
14
+ export interface UnmigratableApp extends BaseMigrationApp {
15
+ isMigratable: false;
16
+ unmigratableReason: keyof typeof UNMIGRATABLE_REASONS;
17
+ }
18
+ export type MigrationApp = MigratableApp | UnmigratableApp;
19
+ export interface ListAppsResponse {
20
+ migratableApps: MigratableApp[];
21
+ unmigratableApps: UnmigratableApp[];
22
+ }
23
+ export interface InitializeMigrationResponse {
24
+ migrationId: number;
25
+ }
26
+ export interface ListAppsMigrationComponent {
27
+ id: string;
28
+ componentType: string;
29
+ isSupported: boolean;
30
+ }
31
+ export type ContinueMigrationResponse = {
32
+ migrationId: number;
33
+ };
34
+ export interface MigrationBaseStatus {
35
+ id: number;
36
+ }
37
+ export interface MigrationInProgress extends MigrationBaseStatus {
38
+ status: typeof MIGRATION_STATUS.IN_PROGRESS;
39
+ }
40
+ export interface MigrationInputRequired extends MigrationBaseStatus {
41
+ status: typeof MIGRATION_STATUS.INPUT_REQUIRED;
42
+ componentsRequiringUids: Record<string, {
43
+ componentType: string;
44
+ componentHint: string;
45
+ }>;
46
+ }
47
+ export interface MigrationSuccess extends MigrationBaseStatus {
48
+ status: typeof MIGRATION_STATUS.SUCCESS;
49
+ buildId: number;
50
+ }
51
+ export interface MigrationFailed extends MigrationBaseStatus {
52
+ status: typeof MIGRATION_STATUS.FAILURE;
53
+ projectErrorsDetail?: string;
54
+ componentErrorDetails: Record<string, string>;
55
+ }
56
+ export type MigrationStatus = MigrationInProgress | MigrationInputRequired | MigrationSuccess | MigrationFailed;
57
+ export declare function listAppsForMigration(accountId: number): HubSpotPromise<ListAppsResponse>;
58
+ export declare function initializeMigration(accountId: number, applicationId: number, platformVersion: string): HubSpotPromise<InitializeMigrationResponse>;
59
+ export declare function continueMigration(portalId: number, migrationId: number, componentUids: Record<string, string>, projectName: string): HubSpotPromise<ContinueMigrationResponse>;
60
+ export declare function checkMigrationStatusV2(accountId: number, id: number): HubSpotPromise<MigrationStatus>;
61
+ export {};
package/api/migrate.js ADDED
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listAppsForMigration = listAppsForMigration;
4
+ exports.initializeMigration = initializeMigration;
5
+ exports.continueMigration = continueMigration;
6
+ exports.checkMigrationStatusV2 = checkMigrationStatusV2;
7
+ const projects_1 = require("@hubspot/local-dev-lib/constants/projects");
8
+ const http_1 = require("@hubspot/local-dev-lib/http");
9
+ const MIGRATIONS_API_PATH_V2 = 'dfs/migrations/v2';
10
+ async function listAppsForMigration(accountId) {
11
+ return http_1.http.get(accountId, {
12
+ url: `${MIGRATIONS_API_PATH_V2}/list-apps`,
13
+ });
14
+ }
15
+ function mapPlatformVersionToEnum(platformVersion) {
16
+ if (platformVersion === projects_1.PLATFORM_VERSIONS.unstable) {
17
+ return projects_1.PLATFORM_VERSIONS.unstable.toUpperCase();
18
+ }
19
+ return `V${platformVersion.replace('.', '_')}`;
20
+ }
21
+ async function initializeMigration(accountId, applicationId, platformVersion) {
22
+ return http_1.http.post(accountId, {
23
+ url: `${MIGRATIONS_API_PATH_V2}/migrations`,
24
+ data: {
25
+ applicationId,
26
+ platformVersion: mapPlatformVersionToEnum(platformVersion),
27
+ },
28
+ });
29
+ }
30
+ async function continueMigration(portalId, migrationId, componentUids, projectName) {
31
+ return http_1.http.post(portalId, {
32
+ url: `${MIGRATIONS_API_PATH_V2}/migrations/continue`,
33
+ data: {
34
+ migrationId,
35
+ projectName,
36
+ componentUids,
37
+ },
38
+ });
39
+ }
40
+ function checkMigrationStatusV2(accountId, id) {
41
+ return http_1.http.get(accountId, {
42
+ url: `${MIGRATIONS_API_PATH_V2}/migrations/${id}/status`,
43
+ });
44
+ }
@@ -3,16 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.validMigrationTargets = void 0;
4
4
  exports.handler = handler;
5
5
  exports.builder = builder;
6
+ const logger_1 = require("@hubspot/local-dev-lib/logger");
7
+ const config_1 = require("@hubspot/local-dev-lib/config");
8
+ const projects_1 = require("@hubspot/local-dev-lib/constants/projects");
6
9
  const commonOpts_1 = require("../../lib/commonOpts");
7
10
  const usageTracking_1 = require("../../lib/usageTracking");
8
11
  const lang_1 = require("../../lib/lang");
9
12
  const errorHandlers_1 = require("../../lib/errorHandlers");
10
13
  const exitCodes_1 = require("../../lib/enums/exitCodes");
11
- const config_1 = require("@hubspot/local-dev-lib/config");
12
14
  const migrate_1 = require("../../lib/app/migrate");
13
- const projects_1 = require("@hubspot/local-dev-lib/constants/projects");
14
- const logger_1 = require("@hubspot/local-dev-lib/logger");
15
15
  const ui_1 = require("../../lib/ui");
16
+ const migrate_legacy_1 = require("../../lib/app/migrate_legacy");
16
17
  const { v2023_2, v2025_2, unstable } = projects_1.PLATFORM_VERSIONS;
17
18
  exports.validMigrationTargets = [v2023_2, v2025_2, unstable];
18
19
  const command = 'migrate';
@@ -34,7 +35,7 @@ async function handler(options) {
34
35
  await (0, migrate_1.migrateApp2025_2)(derivedAccountId, options);
35
36
  }
36
37
  else {
37
- await (0, migrate_1.migrateApp2023_2)(derivedAccountId, options, accountConfig);
38
+ await (0, migrate_legacy_1.migrateApp2023_2)(derivedAccountId, options, accountConfig);
38
39
  }
39
40
  }
40
41
  catch (error) {
package/lang/en.lyaml CHANGED
@@ -597,6 +597,7 @@ en:
597
597
  projectAlreadyExists: "A project with name {{ projectName }} already exists. Please choose another name."
598
598
  invalidApp: "Could not migrate appId {{ appId }}. This app cannot be migrated at this time. Please choose another public app."
599
599
  appWithAppIdNotFound: "Could not find an app with the id {{ appId }} "
600
+ migrationFailed: 'Migration Failed'
600
601
  prompt:
601
602
  chooseApp: 'Which app would you like to migrate?'
602
603
  inputName: '[--name] What would you like to name the project?'
@@ -1,7 +1,5 @@
1
- import { CLIAccount } from '@hubspot/local-dev-lib/types/Accounts';
2
1
  import { ArgumentsCamelCase } from 'yargs';
3
2
  import { MigrateAppOptions } from '../../types/Yargs';
4
3
  export declare function downloadProjectFiles(derivedAccountId: number, projectName: string, buildId: number, projectDest: string): Promise<void>;
5
4
  export declare function migrateApp2025_2(derivedAccountId: number, options: ArgumentsCamelCase<MigrateAppOptions>): Promise<void>;
6
5
  export declare function logInvalidAccountError(i18nKey: string): void;
7
- export declare function migrateApp2023_2(derivedAccountId: number, options: ArgumentsCamelCase<MigrateAppOptions>, accountConfig: CLIAccount): Promise<void>;
@@ -6,39 +6,30 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.downloadProjectFiles = downloadProjectFiles;
7
7
  exports.migrateApp2025_2 = migrateApp2025_2;
8
8
  exports.logInvalidAccountError = logInvalidAccountError;
9
- exports.migrateApp2023_2 = migrateApp2023_2;
10
- const promptUtils_1 = require("../prompts/promptUtils");
11
- const errorHandlers_1 = require("../errorHandlers");
12
- const exitCodes_1 = require("../enums/exitCodes");
13
9
  const logger_1 = require("@hubspot/local-dev-lib/logger");
14
- const ui_1 = require("../ui");
15
- const lang_1 = require("../lang");
16
- const accountTypes_1 = require("../accountTypes");
17
- const selectPublicAppPrompt_1 = require("../prompts/selectPublicAppPrompt");
18
- const appsDev_1 = require("@hubspot/local-dev-lib/api/appsDev");
19
- const createProjectPrompt_1 = require("../prompts/createProjectPrompt");
20
- const projects_1 = require("../projects");
21
- const usageTracking_1 = require("../usageTracking");
22
- const SpinniesManager_1 = __importDefault(require("../ui/SpinniesManager"));
23
- const process_1 = require("../process");
24
- const projects_2 = require("@hubspot/local-dev-lib/api/projects");
25
- const polling_1 = require("../polling");
26
10
  const path_1 = __importDefault(require("path"));
27
11
  const path_2 = require("@hubspot/local-dev-lib/path");
28
- const urls_1 = require("@hubspot/local-dev-lib/urls");
29
12
  const archive_1 = require("@hubspot/local-dev-lib/archive");
30
13
  const chalk_1 = __importDefault(require("chalk"));
31
14
  const project_parsing_lib_1 = require("@hubspot/project-parsing-lib");
32
- const projects_3 = require("@hubspot/local-dev-lib/constants/projects");
15
+ const projects_1 = require("@hubspot/local-dev-lib/constants/projects");
33
16
  const transform_1 = require("@hubspot/project-parsing-lib/src/lib/transform");
34
- const index_1 = require("@hubspot/local-dev-lib/errors/index");
17
+ const Migration_1 = require("@hubspot/local-dev-lib/types/Migration");
18
+ const projects_2 = require("@hubspot/local-dev-lib/api/projects");
19
+ const promptUtils_1 = require("../prompts/promptUtils");
20
+ const ui_1 = require("../ui");
21
+ const lang_1 = require("../lang");
22
+ const projects_3 = require("../projects");
23
+ const SpinniesManager_1 = __importDefault(require("../ui/SpinniesManager"));
24
+ const polling_1 = require("../polling");
25
+ const migrate_1 = require("../../api/migrate");
35
26
  function getUnmigratableReason(reasonCode) {
36
27
  switch (reasonCode) {
37
- case projects_3.UNMIGRATABLE_REASONS.UP_TO_DATE:
28
+ case projects_1.UNMIGRATABLE_REASONS.UP_TO_DATE:
38
29
  return (0, lang_1.i18n)('commands.project.subcommands.migrateApp.unmigratableReasons.upToDate');
39
- case projects_3.UNMIGRATABLE_REASONS.IS_A_PRIVATE_APP:
30
+ case projects_1.UNMIGRATABLE_REASONS.IS_A_PRIVATE_APP:
40
31
  return (0, lang_1.i18n)('commands.project.subcommands.migrateApp.unmigratableReasons.isPrivateApp');
41
- case projects_3.UNMIGRATABLE_REASONS.LISTED_IN_MARKETPLACE:
32
+ case projects_1.UNMIGRATABLE_REASONS.LISTED_IN_MARKETPLACE:
42
33
  return (0, lang_1.i18n)('commands.project.subcommands.migrateApp.unmigratableReasons.listedInMarketplace');
43
34
  default:
44
35
  return (0, lang_1.i18n)('commands.project.subcommands.migrateApp.unmigratableReasons.generic', {
@@ -48,7 +39,7 @@ function getUnmigratableReason(reasonCode) {
48
39
  }
49
40
  async function handleMigrationSetup(derivedAccountId, options) {
50
41
  const { name, dest, appId } = options;
51
- const { data } = await (0, projects_2.listAppsForMigration)(derivedAccountId);
42
+ const { data } = await (0, migrate_1.listAppsForMigration)(derivedAccountId);
52
43
  const { migratableApps, unmigratableApps } = data;
53
44
  const allApps = [...migratableApps, ...unmigratableApps].filter(app => !app.projectName);
54
45
  if (allApps.length === 0) {
@@ -114,7 +105,7 @@ async function handleMigrationSetup(derivedAccountId, options) {
114
105
  }
115
106
  const projectName = name ||
116
107
  (await (0, promptUtils_1.inputPrompt)((0, lang_1.i18n)('commands.project.subcommands.migrateApp.prompt.inputName')));
117
- const { projectExists } = await (0, projects_1.ensureProjectExists)(derivedAccountId, projectName, { forceCreate: false, allowCreate: false, noLogs: true });
108
+ const { projectExists } = await (0, projects_3.ensureProjectExists)(derivedAccountId, projectName, { allowCreate: false, noLogs: true });
118
109
  if (projectExists) {
119
110
  throw new Error((0, lang_1.i18n)('commands.project.subcommands.migrateApp.errors.projectAlreadyExists', {
120
111
  projectName,
@@ -131,10 +122,10 @@ async function beginMigration(derivedAccountId, appId, platformVersion) {
131
122
  text: (0, lang_1.i18n)('commands.project.subcommands.migrateApp.spinners.beginningMigration'),
132
123
  });
133
124
  const uidMap = {};
134
- const { data } = await (0, projects_2.initializeMigration)(derivedAccountId, appId, platformVersion);
125
+ const { data } = await (0, migrate_1.initializeMigration)(derivedAccountId, appId, platformVersion);
135
126
  const { migrationId } = data;
136
- const pollResponse = await pollMigrationStatus(derivedAccountId, migrationId, ['INPUT_REQUIRED']);
137
- if (pollResponse.status !== 'INPUT_REQUIRED') {
127
+ const pollResponse = await pollMigrationStatus(derivedAccountId, migrationId, [Migration_1.MIGRATION_STATUS.INPUT_REQUIRED]);
128
+ if (pollResponse.status !== Migration_1.MIGRATION_STATUS.INPUT_REQUIRED) {
138
129
  SpinniesManager_1.default.fail('beginningMigration', {
139
130
  text: (0, lang_1.i18n)('commands.project.subcommands.migrateApp.spinners.unableToStartMigration'),
140
131
  });
@@ -159,31 +150,21 @@ async function beginMigration(derivedAccountId, appId, platformVersion) {
159
150
  return { migrationId, uidMap };
160
151
  }
161
152
  async function pollMigrationStatus(derivedAccountId, migrationId, successStates = []) {
162
- return (0, polling_1.poll)(() => (0, projects_2.checkMigrationStatusV2)(derivedAccountId, migrationId), {
153
+ return (0, polling_1.poll)(() => (0, migrate_1.checkMigrationStatusV2)(derivedAccountId, migrationId), {
163
154
  successStates: [...successStates],
164
155
  errorStates: [...polling_1.DEFAULT_POLLING_STATUS_LOOKUP.errorStates],
165
156
  });
166
157
  }
167
158
  async function finalizeMigration(derivedAccountId, migrationId, uidMap, projectName) {
168
- let buildId;
159
+ let pollResponse;
169
160
  try {
170
161
  SpinniesManager_1.default.add('finishingMigration', {
171
162
  text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.finishingMigration`),
172
163
  });
173
- await (0, projects_2.continueMigration)(derivedAccountId, migrationId, uidMap, projectName);
174
- const pollResponse = await pollMigrationStatus(derivedAccountId, migrationId, ['SUCCESS']);
175
- if (pollResponse.status === 'SUCCESS') {
176
- buildId = pollResponse.buildId;
177
- SpinniesManager_1.default.succeed('finishingMigration', {
178
- text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.migrationComplete`),
179
- });
180
- }
181
- else {
182
- SpinniesManager_1.default.fail('finishingMigration', {
183
- text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.migrationFailed`),
184
- });
185
- }
186
- return buildId;
164
+ await (0, migrate_1.continueMigration)(derivedAccountId, migrationId, uidMap, projectName);
165
+ pollResponse = await pollMigrationStatus(derivedAccountId, migrationId, [
166
+ Migration_1.MIGRATION_STATUS.SUCCESS,
167
+ ]);
187
168
  }
188
169
  catch (error) {
189
170
  SpinniesManager_1.default.fail('finishingMigration', {
@@ -191,6 +172,22 @@ async function finalizeMigration(derivedAccountId, migrationId, uidMap, projectN
191
172
  });
192
173
  throw error;
193
174
  }
175
+ if (pollResponse.status === Migration_1.MIGRATION_STATUS.SUCCESS) {
176
+ SpinniesManager_1.default.succeed('finishingMigration', {
177
+ text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.migrationComplete`),
178
+ });
179
+ return pollResponse.buildId;
180
+ }
181
+ else {
182
+ SpinniesManager_1.default.fail('finishingMigration', {
183
+ text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.migrationFailed`),
184
+ });
185
+ if (pollResponse.status === Migration_1.MIGRATION_STATUS.FAILURE) {
186
+ logger_1.logger.error(pollResponse.componentErrorDetails);
187
+ throw new Error(pollResponse.projectErrorsDetail);
188
+ }
189
+ throw new Error((0, lang_1.i18n)('commands.project.subcommands.migrateApp.errors.migrationFailed'));
190
+ }
194
191
  }
195
192
  async function downloadProjectFiles(derivedAccountId, projectName, buildId, projectDest) {
196
193
  try {
@@ -229,9 +226,6 @@ async function migrateApp2025_2(derivedAccountId, options) {
229
226
  }
230
227
  const { migrationId, uidMap } = migrationInProgress;
231
228
  const buildId = await finalizeMigration(derivedAccountId, migrationId, uidMap, projectName);
232
- if (!buildId) {
233
- throw new Error('Migration Failed');
234
- }
235
229
  await downloadProjectFiles(derivedAccountId, projectName, buildId, projectDest);
236
230
  }
237
231
  function logInvalidAccountError(i18nKey) {
@@ -243,123 +237,3 @@ function logInvalidAccountError(i18nKey) {
243
237
  }));
244
238
  (0, ui_1.uiLine)();
245
239
  }
246
- async function migrateApp2023_2(derivedAccountId, options, accountConfig) {
247
- const i18nKey = 'commands.project.subcommands.migrateApp';
248
- const accountName = (0, ui_1.uiAccountDescription)(derivedAccountId);
249
- if (!(0, accountTypes_1.isAppDeveloperAccount)(accountConfig)) {
250
- logInvalidAccountError(i18nKey);
251
- process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
252
- }
253
- const { appId } = 'appId' in options
254
- ? options
255
- : await (0, selectPublicAppPrompt_1.selectPublicAppPrompt)({
256
- accountId: derivedAccountId,
257
- accountName,
258
- isMigratingApp: true,
259
- });
260
- try {
261
- const { data: selectedApp } = await (0, appsDev_1.fetchPublicAppMetadata)(appId, derivedAccountId);
262
- // preventProjectMigrations returns true if we have not added app to allowlist config.
263
- // listingInfo will only exist for marketplace apps
264
- const preventProjectMigrations = selectedApp.preventProjectMigrations;
265
- const listingInfo = selectedApp.listingInfo;
266
- if (preventProjectMigrations && listingInfo) {
267
- logger_1.logger.error((0, lang_1.i18n)(`${i18nKey}.errors.invalidApp`, { appId }));
268
- process.exit(exitCodes_1.EXIT_CODES.ERROR);
269
- }
270
- }
271
- catch (error) {
272
- (0, errorHandlers_1.logError)(error, new errorHandlers_1.ApiErrorContext({ accountId: derivedAccountId }));
273
- process.exit(exitCodes_1.EXIT_CODES.ERROR);
274
- }
275
- const createProjectPromptResponse = await (0, createProjectPrompt_1.createProjectPrompt)(options);
276
- const { name: projectName, dest: projectDest } = createProjectPromptResponse;
277
- try {
278
- await (0, projects_2.fetchProject)(derivedAccountId, projectName);
279
- throw new Error((0, lang_1.i18n)(`${i18nKey}.errors.projectAlreadyExists`, {
280
- projectName,
281
- }));
282
- }
283
- catch (error) {
284
- if (!(0, index_1.isSpecifiedError)(error, { statusCode: 404 })) {
285
- (0, errorHandlers_1.logError)(error, new errorHandlers_1.ApiErrorContext({ accountId: derivedAccountId }));
286
- return process.exit(exitCodes_1.EXIT_CODES.ERROR);
287
- }
288
- }
289
- // const { projectExists } = await ensureProjectExists(
290
- // derivedAccountId,
291
- // projectName,
292
- // {
293
- // allowCreate: false,
294
- // noLogs: true,
295
- // }
296
- // );
297
- //
298
- // if (projectExists) {
299
- // throw new Error(
300
- // i18n(`${i18nKey}.errors.projectAlreadyExists`, {
301
- // projectName,
302
- // })
303
- // );
304
- // }
305
- await (0, usageTracking_1.trackCommandMetadataUsage)('migrate-app', { step: 'STARTED' }, derivedAccountId);
306
- logger_1.logger.log('');
307
- (0, ui_1.uiLine)();
308
- logger_1.logger.warn(`${(0, lang_1.i18n)(`${i18nKey}.warning.title`)}\n`);
309
- logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.warning.projectConversion`));
310
- logger_1.logger.log(`${(0, lang_1.i18n)(`${i18nKey}.warning.appConfig`)}\n`);
311
- logger_1.logger.log(`${(0, lang_1.i18n)(`${i18nKey}.warning.buildAndDeploy`)}\n`);
312
- logger_1.logger.log(`${(0, lang_1.i18n)(`${i18nKey}.warning.existingApps`)}\n`);
313
- logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.warning.copyApp`));
314
- (0, ui_1.uiLine)();
315
- const { shouldCreateApp } = await (0, promptUtils_1.promptUser)({
316
- name: 'shouldCreateApp',
317
- type: 'confirm',
318
- message: (0, lang_1.i18n)(`${i18nKey}.createAppPrompt`),
319
- });
320
- process.stdin.resume();
321
- if (!shouldCreateApp) {
322
- process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
323
- }
324
- try {
325
- SpinniesManager_1.default.init();
326
- SpinniesManager_1.default.add('migrateApp', {
327
- text: (0, lang_1.i18n)(`${i18nKey}.migrationStatus.inProgress`),
328
- });
329
- (0, process_1.handleKeypress)(async (key) => {
330
- if ((key.ctrl && key.name === 'c') || key.name === 'q') {
331
- SpinniesManager_1.default.remove('migrateApp');
332
- logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.migrationInterrupted`));
333
- process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
334
- }
335
- });
336
- const { data: migrateResponse } = await (0, projects_2.migrateApp)(derivedAccountId, appId, projectName);
337
- const { id } = migrateResponse;
338
- const pollResponse = await (0, polling_1.poll)(() => (0, projects_2.checkMigrationStatus)(derivedAccountId, id));
339
- const { status, project } = pollResponse;
340
- if (status === 'SUCCESS') {
341
- const absoluteDestPath = path_1.default.resolve((0, path_2.getCwd)(), projectDest);
342
- const { env } = accountConfig;
343
- const baseUrl = (0, urls_1.getHubSpotWebsiteOrigin)(env);
344
- const { data: zippedProject } = await (0, projects_2.downloadProject)(derivedAccountId, projectName, 1);
345
- await (0, archive_1.extractZipArchive)(zippedProject, (0, path_2.sanitizeFileName)(projectName), path_1.default.resolve(absoluteDestPath), { includesRootDir: true, hideLogs: true });
346
- SpinniesManager_1.default.succeed('migrateApp', {
347
- text: (0, lang_1.i18n)(`${i18nKey}.migrationStatus.done`),
348
- succeedColor: 'white',
349
- });
350
- logger_1.logger.log('');
351
- (0, ui_1.uiLine)();
352
- logger_1.logger.success((0, lang_1.i18n)(`${i18nKey}.migrationStatus.success`));
353
- logger_1.logger.log('');
354
- logger_1.logger.log((0, ui_1.uiLink)((0, lang_1.i18n)(`${i18nKey}.projectDetailsLink`), `${baseUrl}/developer-projects/${derivedAccountId}/project/${encodeURIComponent(project.name)}`));
355
- process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
356
- }
357
- }
358
- catch (error) {
359
- SpinniesManager_1.default.fail('migrateApp', {
360
- text: (0, lang_1.i18n)(`${i18nKey}.migrationStatus.failure`),
361
- failColor: 'white',
362
- });
363
- throw error;
364
- }
365
- }
@@ -0,0 +1,4 @@
1
+ import { CLIAccount } from '@hubspot/local-dev-lib/types/Accounts';
2
+ import { ArgumentsCamelCase } from 'yargs';
3
+ import { MigrateAppOptions } from '../../types/Yargs';
4
+ export declare function migrateApp2023_2(derivedAccountId: number, options: ArgumentsCamelCase<MigrateAppOptions>, accountConfig: CLIAccount): Promise<void>;
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.migrateApp2023_2 = migrateApp2023_2;
7
+ const appsDev_1 = require("@hubspot/local-dev-lib/api/appsDev");
8
+ const logger_1 = require("@hubspot/local-dev-lib/logger");
9
+ const projects_1 = require("@hubspot/local-dev-lib/api/projects");
10
+ const path_1 = __importDefault(require("path"));
11
+ const path_2 = require("@hubspot/local-dev-lib/path");
12
+ const urls_1 = require("@hubspot/local-dev-lib/urls");
13
+ const archive_1 = require("@hubspot/local-dev-lib/archive");
14
+ const promptUtils_1 = require("../prompts/promptUtils");
15
+ const errorHandlers_1 = require("../errorHandlers");
16
+ const exitCodes_1 = require("../enums/exitCodes");
17
+ const ui_1 = require("../ui");
18
+ const lang_1 = require("../lang");
19
+ const accountTypes_1 = require("../accountTypes");
20
+ const selectPublicAppPrompt_1 = require("../prompts/selectPublicAppPrompt");
21
+ const createProjectPrompt_1 = require("../prompts/createProjectPrompt");
22
+ const projects_2 = require("../projects");
23
+ const usageTracking_1 = require("../usageTracking");
24
+ const SpinniesManager_1 = __importDefault(require("../ui/SpinniesManager"));
25
+ const process_1 = require("../process");
26
+ const polling_1 = require("../polling");
27
+ const migrate_1 = require("./migrate");
28
+ async function migrateApp2023_2(derivedAccountId, options, accountConfig) {
29
+ const accountName = (0, ui_1.uiAccountDescription)(derivedAccountId);
30
+ if (!(0, accountTypes_1.isAppDeveloperAccount)(accountConfig)) {
31
+ (0, migrate_1.logInvalidAccountError)('commands.project.subcommands.migrateApp');
32
+ process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
33
+ }
34
+ const { appId } = 'appId' in options
35
+ ? options
36
+ : await (0, selectPublicAppPrompt_1.selectPublicAppPrompt)({
37
+ accountId: derivedAccountId,
38
+ accountName,
39
+ isMigratingApp: true,
40
+ });
41
+ try {
42
+ const { data: selectedApp } = await (0, appsDev_1.fetchPublicAppMetadata)(appId, derivedAccountId);
43
+ // preventProjectMigrations returns true if we have not added app to allowlist config.
44
+ // listingInfo will only exist for marketplace apps
45
+ const preventProjectMigrations = selectedApp.preventProjectMigrations;
46
+ const listingInfo = selectedApp.listingInfo;
47
+ if (preventProjectMigrations && listingInfo) {
48
+ logger_1.logger.error((0, lang_1.i18n)(`commands.project.subcommands.migrateApp.errors.invalidApp`, {
49
+ appId,
50
+ }));
51
+ process.exit(exitCodes_1.EXIT_CODES.ERROR);
52
+ }
53
+ }
54
+ catch (error) {
55
+ (0, errorHandlers_1.logError)(error, new errorHandlers_1.ApiErrorContext({ accountId: derivedAccountId }));
56
+ process.exit(exitCodes_1.EXIT_CODES.ERROR);
57
+ }
58
+ const createProjectPromptResponse = await (0, createProjectPrompt_1.createProjectPrompt)(options);
59
+ const { name: projectName, dest: projectDest } = createProjectPromptResponse;
60
+ const { projectExists } = await (0, projects_2.ensureProjectExists)(derivedAccountId, projectName, {
61
+ allowCreate: false,
62
+ noLogs: true,
63
+ });
64
+ if (projectExists) {
65
+ throw new Error((0, lang_1.i18n)(`commands.project.subcommands.migrateApp.errors.projectAlreadyExists`, {
66
+ projectName,
67
+ }));
68
+ }
69
+ await (0, usageTracking_1.trackCommandMetadataUsage)('migrate-app', { step: 'STARTED' }, derivedAccountId);
70
+ logger_1.logger.log('');
71
+ (0, ui_1.uiLine)();
72
+ logger_1.logger.warn(`${(0, lang_1.i18n)(`commands.project.subcommands.migrateApp.warning.title`)}\n`);
73
+ logger_1.logger.log((0, lang_1.i18n)(`commands.project.subcommands.migrateApp.warning.projectConversion`));
74
+ logger_1.logger.log(`${(0, lang_1.i18n)(`commands.project.subcommands.migrateApp.warning.appConfig`)}\n`);
75
+ logger_1.logger.log(`${(0, lang_1.i18n)(`commands.project.subcommands.migrateApp.warning.buildAndDeploy`)}\n`);
76
+ logger_1.logger.log(`${(0, lang_1.i18n)(`commands.project.subcommands.migrateApp.warning.existingApps`)}\n`);
77
+ logger_1.logger.log((0, lang_1.i18n)(`commands.project.subcommands.migrateApp.warning.copyApp`));
78
+ (0, ui_1.uiLine)();
79
+ const { shouldCreateApp } = await (0, promptUtils_1.promptUser)({
80
+ name: 'shouldCreateApp',
81
+ type: 'confirm',
82
+ message: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.createAppPrompt`),
83
+ });
84
+ process.stdin.resume();
85
+ if (!shouldCreateApp) {
86
+ process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
87
+ }
88
+ try {
89
+ SpinniesManager_1.default.init();
90
+ SpinniesManager_1.default.add('migrateApp', {
91
+ text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.migrationStatus.inProgress`),
92
+ });
93
+ (0, process_1.handleKeypress)(async (key) => {
94
+ if ((key.ctrl && key.name === 'c') || key.name === 'q') {
95
+ SpinniesManager_1.default.remove('migrateApp');
96
+ logger_1.logger.log((0, lang_1.i18n)(`commands.project.subcommands.migrateApp.migrationInterrupted`));
97
+ process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
98
+ }
99
+ });
100
+ const { data: migrateResponse } = await (0, projects_1.migrateApp)(derivedAccountId, appId, projectName);
101
+ const { id } = migrateResponse;
102
+ const pollResponse = await (0, polling_1.poll)(() => (0, projects_1.checkMigrationStatus)(derivedAccountId, id));
103
+ const { status, project } = pollResponse;
104
+ if (status === 'SUCCESS') {
105
+ const absoluteDestPath = path_1.default.resolve((0, path_2.getCwd)(), projectDest);
106
+ const { env } = accountConfig;
107
+ const baseUrl = (0, urls_1.getHubSpotWebsiteOrigin)(env);
108
+ const { data: zippedProject } = await (0, projects_1.downloadProject)(derivedAccountId, projectName, 1);
109
+ await (0, archive_1.extractZipArchive)(zippedProject, (0, path_2.sanitizeFileName)(projectName), path_1.default.resolve(absoluteDestPath), { includesRootDir: true, hideLogs: true });
110
+ SpinniesManager_1.default.succeed('migrateApp', {
111
+ text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.migrationStatus.done`),
112
+ succeedColor: 'white',
113
+ });
114
+ logger_1.logger.log('');
115
+ (0, ui_1.uiLine)();
116
+ logger_1.logger.success((0, lang_1.i18n)(`commands.project.subcommands.migrateApp.migrationStatus.success`));
117
+ logger_1.logger.log('');
118
+ logger_1.logger.log((0, ui_1.uiLink)((0, lang_1.i18n)(`commands.project.subcommands.migrateApp.projectDetailsLink`), `${baseUrl}/developer-projects/${derivedAccountId}/project/${encodeURIComponent(project.name)}`));
119
+ process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
120
+ }
121
+ }
122
+ catch (error) {
123
+ SpinniesManager_1.default.fail('migrateApp', {
124
+ text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.migrationStatus.failure`),
125
+ failColor: 'white',
126
+ });
127
+ throw error;
128
+ }
129
+ }
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@hubspot/cli",
3
- "version": "7.4.2-experimental.0",
3
+ "version": "7.4.4-experimental.0",
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
  "dependencies": {
8
- "@hubspot/local-dev-lib": "0.3.0-experimental.0",
8
+ "@hubspot/local-dev-lib": "3.5.1-beta.0",
9
9
  "@hubspot/project-parsing-lib": "0.1.5",
10
10
  "@hubspot/serverless-dev-runtime": "7.0.2",
11
11
  "@hubspot/theme-preview-dev-server": "0.0.10",