@hubspot/cli 7.4.1 → 7.4.2-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lang/en.lyaml CHANGED
@@ -650,37 +650,12 @@ en:
650
650
  componentsToBeMigrated: "The following component types will be migrated: {{ components }}"
651
651
  componentsThatWillNotBeMigrated: "[NOTE] These component types are not yet supported for migration but will be available later: {{ components }}"
652
652
  errors:
653
- noAppsEligible: "No apps in account {{ accountId }} are currently migratable"
653
+ noAppsForProject: "No apps associated with project {{ projectName }}"
654
654
  noAccountConfig: "There is no account associated with {{ accountId }} in the config file. Please choose another account and try again, or authenticate {{ accountId }} using {{ authCommand }}."
655
- invalidAccountTypeTitle: "{{#bold}}Developer account not targeted{{/bold}}"
656
- invalidAccountTypeDescription: "Only public apps created in a developer account can be converted to a project component. Select a connected developer account with {{useCommand}} or {{authCommand}} and try again."
657
655
  projectAlreadyExists: "A project with name {{ projectName }} already exists. Please choose another name."
658
656
  invalidApp: "Could not migrate appId {{ appId }}. This app cannot be migrated at this time. Please choose another public app."
659
- appWithAppIdNotFound: "Could not find an app with the id {{ appId }} "
660
657
  migrationFailed: 'Migration Failed'
661
- prompt:
662
- chooseApp: 'Which app would you like to migrate?'
663
- inputName: '[--name] What would you like to name the project?'
664
- inputDest: '[--dest] Where would you like to save the project?'
665
- uidForComponent: 'What UID would you like to use for {{ componentName }}?'
666
- proceed: 'Would you like to proceed?'
667
- spinners:
668
- beginningMigration: "Beginning migration"
669
- unableToStartMigration: "Unable to begin migration"
670
- finishingMigration: "Wrapping up migration"
671
- migrationComplete: "Migration completed"
672
- migrationFailed: "Migration failed"
673
- downloadingProjectContents: "Downloading migrated project files"
674
- downloadingProjectContentsComplete: "Migrated project files downloaded"
675
- downloadingProjectContentsFailed: "Unable to download migrated project files"
676
- copyingProjectFiles: "Copying migrated project files"
677
- copyingProjectFilesComplete: "Migrated project files copied"
678
- copyingProjectFilesFailed: "Unable to copy migrated project files"
679
- unmigratableReasons:
680
- upToDate: 'App is already up to date'
681
- isPrivateApp: 'Private apps are not currently migratable'
682
- listedInMarketplace: 'Listed apps are not currently migratable'
683
- generic: "Unable to migrate app: {{ reasonCode }}"
658
+ notAllowedWithinProject: 'This command cannot be run from within a project directory. Run the command again from outside a project directory. If you are trying to migrate a project, run {{ command }}'
684
659
  cloneApp:
685
660
  describe: "Clone a public app using the projects framework."
686
661
  examples:
@@ -717,6 +692,12 @@ en:
717
692
  examples:
718
693
  default: "Create a component within your project"
719
694
  withFlags: "Use --name and --type flags to bypass the prompt."
695
+ migrate:
696
+ describe: "Migrate an existing project to the new version of the projects framework."
697
+ errors:
698
+ noProjectConfig: "No project detected. Please run this command again from a project directory."
699
+ examples:
700
+ default: "Migrate an existing project to the new version of the projects framework."
720
701
  deploy:
721
702
  describe: "Deploy a project build."
722
703
  deployBuildIdPrompt: "[--build] Deploy which build?"
@@ -1,5 +1,11 @@
1
1
  import { ArgumentsCamelCase } from 'yargs';
2
- import { MigrateAppOptions } from '../../types/Yargs';
3
- export declare function downloadProjectFiles(derivedAccountId: number, projectName: string, buildId: number, projectDest: string): Promise<void>;
4
- export declare function migrateApp2025_2(derivedAccountId: number, options: ArgumentsCamelCase<MigrateAppOptions>): Promise<void>;
5
- export declare function logInvalidAccountError(i18nKey: string): void;
2
+ import { LoadedProjectConfig } from '../projects';
3
+ import { AccountArgs, CommonArgs, ConfigArgs, EnvironmentArgs } from '../../types/Yargs';
4
+ export type MigrateAppArgs = CommonArgs & AccountArgs & EnvironmentArgs & ConfigArgs & {
5
+ name?: string;
6
+ dest?: string;
7
+ appId?: number;
8
+ platformVersion: string;
9
+ };
10
+ export declare function migrateApp2025_2(derivedAccountId: number, options: ArgumentsCamelCase<MigrateAppArgs>, projectConfig?: LoadedProjectConfig): Promise<void>;
11
+ export declare function logInvalidAccountError(): void;
@@ -3,7 +3,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.downloadProjectFiles = downloadProjectFiles;
7
6
  exports.migrateApp2025_2 = migrateApp2025_2;
8
7
  exports.logInvalidAccountError = logInvalidAccountError;
9
8
  const logger_1 = require("@hubspot/local-dev-lib/logger");
@@ -18,49 +17,66 @@ const Migration_1 = require("@hubspot/local-dev-lib/types/Migration");
18
17
  const projects_2 = require("@hubspot/local-dev-lib/api/projects");
19
18
  const promptUtils_1 = require("../prompts/promptUtils");
20
19
  const ui_1 = require("../ui");
21
- const lang_1 = require("../lang");
22
20
  const projects_3 = require("../projects");
23
21
  const SpinniesManager_1 = __importDefault(require("../ui/SpinniesManager"));
24
22
  const polling_1 = require("../polling");
25
23
  const migrate_1 = require("../../api/migrate");
24
+ const fs_1 = __importDefault(require("fs"));
25
+ const en_1 = require("../../lang/en");
26
+ const util_1 = __importDefault(require("util"));
27
+ const hasFeature_1 = require("../hasFeature");
26
28
  function getUnmigratableReason(reasonCode) {
27
29
  switch (reasonCode) {
28
30
  case projects_1.UNMIGRATABLE_REASONS.UP_TO_DATE:
29
- return (0, lang_1.i18n)('commands.project.subcommands.migrateApp.unmigratableReasons.upToDate');
31
+ return en_1.lib.migrate.errors.unmigratableReasons.upToDate;
30
32
  case projects_1.UNMIGRATABLE_REASONS.IS_A_PRIVATE_APP:
31
- return (0, lang_1.i18n)('commands.project.subcommands.migrateApp.unmigratableReasons.isPrivateApp');
33
+ return en_1.lib.migrate.errors.unmigratableReasons.isPrivateApp;
32
34
  case projects_1.UNMIGRATABLE_REASONS.LISTED_IN_MARKETPLACE:
33
- return (0, lang_1.i18n)('commands.project.subcommands.migrateApp.unmigratableReasons.listedInMarketplace');
35
+ return en_1.lib.migrate.errors.unmigratableReasons.listedInMarketplace;
34
36
  default:
35
- return (0, lang_1.i18n)('commands.project.subcommands.migrateApp.unmigratableReasons.generic', {
36
- reasonCode,
37
- });
37
+ return en_1.lib.migrate.errors.unmigratableReasons.generic(reasonCode);
38
38
  }
39
39
  }
40
- async function handleMigrationSetup(derivedAccountId, options) {
41
- const { name, dest, appId } = options;
42
- const { data: { migratableApps, unmigratableApps }, } = await (0, migrate_1.listAppsForMigration)(derivedAccountId);
43
- const migratableAppsWithoutProject = migratableApps.filter((app) => !app.projectName);
44
- const unmigratableAppsWithoutProject = unmigratableApps.filter((app) => !app.projectName);
45
- const allAppsWithoutProject = [
46
- ...migratableAppsWithoutProject,
47
- ...unmigratableAppsWithoutProject,
48
- ];
49
- if (allAppsWithoutProject.length === 0) {
50
- const reasons = unmigratableAppsWithoutProject.map(app => `${chalk_1.default.bold(app.appName)}: ${getUnmigratableReason(app.unmigratableReason)}`);
51
- throw new Error(`${(0, lang_1.i18n)(`commands.project.subcommands.migrateApp.errors.noAppsEligible`, {
52
- accountId: (0, ui_1.uiAccountDescription)(derivedAccountId),
53
- })}${reasons.length ? `\n - ${reasons.join('\n - ')}` : ''}`);
40
+ function filterAppsByProjectName(projectConfig) {
41
+ return (app) => {
42
+ if (projectConfig) {
43
+ return app.projectName === projectConfig?.projectConfig?.name;
44
+ }
45
+ return !app.projectName;
46
+ };
47
+ }
48
+ async function fetchMigrationApps(appId, derivedAccountId, platformVersion, projectConfig) {
49
+ const { data: { migratableApps, unmigratableApps }, } = await (0, migrate_1.listAppsForMigration)(derivedAccountId, platformVersion);
50
+ const filteredMigratableApps = migratableApps.filter(filterAppsByProjectName(projectConfig));
51
+ const filteredUnmigratableApps = unmigratableApps.filter(filterAppsByProjectName(projectConfig));
52
+ const allApps = [...filteredMigratableApps, ...filteredUnmigratableApps];
53
+ if (allApps.length > 1 && projectConfig) {
54
+ throw new Error(en_1.lib.migrate.errors.project.multipleApps);
55
+ }
56
+ if (allApps.length === 0 && projectConfig) {
57
+ throw new Error(en_1.lib.migrate.errors.noAppsForProject(projectConfig?.projectConfig?.name || ''));
58
+ }
59
+ if (allApps.length === 0 ||
60
+ filteredUnmigratableApps.length === allApps.length) {
61
+ const reasons = filteredUnmigratableApps.map(app => `${chalk_1.default.bold(app.appName)}: ${getUnmigratableReason(app.unmigratableReason)}`);
62
+ throw new Error(en_1.lib.migrate.errors.noAppsEligible((0, ui_1.uiAccountDescription)(derivedAccountId), reasons));
54
63
  }
55
64
  if (appId &&
56
- !allAppsWithoutProject.some(app => {
65
+ !allApps.some(app => {
57
66
  return app.appId === appId;
58
67
  })) {
59
- throw new Error((0, lang_1.i18n)('commands.project.subcommands.migrateApp.prompt.chooseApp', {
60
- appId,
61
- }));
68
+ throw new Error(en_1.lib.migrate.errors.appWithAppIdNotFound(appId));
62
69
  }
63
- const appChoices = allAppsWithoutProject.map(app => ({
70
+ return allApps;
71
+ }
72
+ async function selectAppToMigrate(allApps, appId) {
73
+ if (appId &&
74
+ !allApps.some(app => {
75
+ return app.appId === appId;
76
+ })) {
77
+ throw new Error(en_1.lib.migrate.errors.appWithAppIdNotFound(appId));
78
+ }
79
+ const appChoices = allApps.map(app => ({
64
80
  name: app.isMigratable
65
81
  ? app.appName
66
82
  : `[${chalk_1.default.yellow('DISABLED')}] ${app.appName} `,
@@ -71,12 +87,12 @@ async function handleMigrationSetup(derivedAccountId, options) {
71
87
  }));
72
88
  let appIdToMigrate = appId;
73
89
  if (!appIdToMigrate) {
74
- const { appId: selectedAppId } = await (0, promptUtils_1.listPrompt)((0, lang_1.i18n)('commands.project.subcommands.migrateApp.prompt.chooseApp'), {
90
+ const { appId: selectedAppId } = await (0, promptUtils_1.listPrompt)(en_1.lib.migrate.prompt.chooseApp, {
75
91
  choices: appChoices,
76
92
  });
77
93
  appIdToMigrate = selectedAppId;
78
94
  }
79
- const selectedApp = allAppsWithoutProject.find(app => app.appId === appIdToMigrate);
95
+ const selectedApp = allApps.find(app => app.appId === appIdToMigrate);
80
96
  const migratableComponents = [];
81
97
  const unmigratableComponents = [];
82
98
  selectedApp?.migrationComponents.forEach(component => {
@@ -88,37 +104,51 @@ async function handleMigrationSetup(derivedAccountId, options) {
88
104
  }
89
105
  });
90
106
  if (migratableComponents.length !== 0) {
91
- logger_1.logger.log((0, lang_1.i18n)('commands.project.subcommands.migrateApp.componentsToBeMigrated', {
92
- components: `\n - ${migratableComponents.join('\n - ')}`,
93
- }));
107
+ logger_1.logger.log(en_1.lib.migrate.componentsToBeMigrated(`\n - ${migratableComponents.join('\n - ')}`));
94
108
  }
95
109
  if (unmigratableComponents.length !== 0) {
96
- logger_1.logger.log((0, lang_1.i18n)('commands.project.subcommands.migrateApp.componentsThatWillNotBeMigrated', {
97
- components: `\n - ${unmigratableComponents.join('\n - ')}`,
98
- }));
110
+ logger_1.logger.log(en_1.lib.migrate.componentsThatWillNotBeMigrated(`\n - ${unmigratableComponents.join('\n - ')}`));
99
111
  }
100
112
  logger_1.logger.log();
101
- const proceed = await (0, promptUtils_1.confirmPrompt)((0, lang_1.i18n)('commands.project.subcommands.migrateApp.prompt.proceed'));
113
+ const proceed = await (0, promptUtils_1.confirmPrompt)(en_1.lib.migrate.prompt.proceed);
114
+ return {
115
+ proceed,
116
+ appIdToMigrate,
117
+ };
118
+ }
119
+ async function handleMigrationSetup(derivedAccountId, options, projectConfig) {
120
+ const { name, dest, appId } = options;
121
+ const allApps = await fetchMigrationApps(appId, derivedAccountId, options.platformVersion, projectConfig);
122
+ const { proceed, appIdToMigrate } = await selectAppToMigrate(allApps, appId);
102
123
  if (!proceed) {
103
124
  return {};
104
125
  }
105
- const projectName = name ||
106
- (await (0, promptUtils_1.inputPrompt)((0, lang_1.i18n)('commands.project.subcommands.migrateApp.prompt.inputName')));
126
+ // If it's a project we don't want to prompt for dest and name, so just return early
127
+ if (projectConfig &&
128
+ projectConfig?.projectConfig &&
129
+ projectConfig?.projectDir) {
130
+ return {
131
+ appIdToMigrate,
132
+ projectName: projectConfig.projectConfig.name,
133
+ projectDest: projectConfig.projectDir,
134
+ };
135
+ }
136
+ const projectName = projectConfig?.projectConfig?.name ||
137
+ name ||
138
+ (await (0, promptUtils_1.inputPrompt)(en_1.lib.migrate.prompt.inputName));
107
139
  const { projectExists } = await (0, projects_3.ensureProjectExists)(derivedAccountId, projectName, { allowCreate: false, noLogs: true });
108
140
  if (projectExists) {
109
- throw new Error((0, lang_1.i18n)('commands.project.subcommands.migrateApp.errors.projectAlreadyExists', {
110
- projectName,
111
- }));
141
+ throw new Error(en_1.lib.migrate.errors.project.alreadyExists(projectName));
112
142
  }
113
143
  const projectDest = dest ||
114
- (await (0, promptUtils_1.inputPrompt)((0, lang_1.i18n)('commands.project.subcommands.migrateApp.prompt.inputDest'), {
144
+ (await (0, promptUtils_1.inputPrompt)(en_1.lib.migrate.prompt.inputDest, {
115
145
  defaultAnswer: path_1.default.resolve((0, path_2.getCwd)(), (0, path_2.sanitizeFileName)(projectName)),
116
146
  }));
117
147
  return { appIdToMigrate, projectName, projectDest };
118
148
  }
119
149
  async function beginMigration(derivedAccountId, appId, platformVersion) {
120
150
  SpinniesManager_1.default.add('beginningMigration', {
121
- text: (0, lang_1.i18n)('commands.project.subcommands.migrateApp.spinners.beginningMigration'),
151
+ text: en_1.lib.migrate.spinners.beginningMigration,
122
152
  });
123
153
  const uidMap = {};
124
154
  const { data } = await (0, migrate_1.initializeMigration)(derivedAccountId, appId, platformVersion);
@@ -126,7 +156,7 @@ async function beginMigration(derivedAccountId, appId, platformVersion) {
126
156
  const pollResponse = await pollMigrationStatus(derivedAccountId, migrationId, [Migration_1.MIGRATION_STATUS.INPUT_REQUIRED]);
127
157
  if (pollResponse.status !== Migration_1.MIGRATION_STATUS.INPUT_REQUIRED) {
128
158
  SpinniesManager_1.default.fail('beginningMigration', {
129
- text: (0, lang_1.i18n)('commands.project.subcommands.migrateApp.spinners.unableToStartMigration'),
159
+ text: en_1.lib.migrate.spinners.unableToStartMigration,
130
160
  });
131
161
  return;
132
162
  }
@@ -135,11 +165,9 @@ async function beginMigration(derivedAccountId, appId, platformVersion) {
135
165
  if (Object.values(componentsRequiringUids).length !== 0) {
136
166
  for (const [componentId, component] of Object.entries(componentsRequiringUids)) {
137
167
  const { componentHint, componentType } = component;
138
- uidMap[componentId] = await (0, promptUtils_1.inputPrompt)((0, lang_1.i18n)('commands.project.subcommands.migrateApp.prompt.uidForComponent', {
139
- componentName: componentHint
140
- ? `${componentHint} [${(0, transform_1.mapToUserFacingType)(componentType)}]`
141
- : (0, transform_1.mapToUserFacingType)(componentType),
142
- }), {
168
+ uidMap[componentId] = await (0, promptUtils_1.inputPrompt)(en_1.lib.migrate.prompt.uidForComponent(componentHint
169
+ ? `${(0, transform_1.mapToUserFacingType)(componentType)} '${componentHint}'`
170
+ : (0, transform_1.mapToUserFacingType)(componentType)), {
143
171
  validate: (uid) => {
144
172
  const result = (0, project_parsing_lib_1.validateUid)(uid);
145
173
  return result === undefined ? true : result;
@@ -162,7 +190,7 @@ async function finalizeMigration(derivedAccountId, migrationId, uidMap, projectN
162
190
  let pollResponse;
163
191
  try {
164
192
  SpinniesManager_1.default.add('finishingMigration', {
165
- text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.finishingMigration`),
193
+ text: en_1.lib.migrate.spinners.finishingMigration,
166
194
  });
167
195
  await (0, migrate_1.continueMigration)(derivedAccountId, migrationId, uidMap, projectName);
168
196
  pollResponse = await pollMigrationStatus(derivedAccountId, migrationId, [
@@ -171,55 +199,78 @@ async function finalizeMigration(derivedAccountId, migrationId, uidMap, projectN
171
199
  }
172
200
  catch (error) {
173
201
  SpinniesManager_1.default.fail('finishingMigration', {
174
- text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.migrationFailed`),
202
+ text: en_1.lib.migrate.spinners.migrationFailed,
175
203
  });
176
- throw error;
204
+ if ((0, migrate_1.isMigrationStatus)(error) && error.status === Migration_1.MIGRATION_STATUS.FAILURE) {
205
+ throw new Error(error.projectErrorDetail);
206
+ }
207
+ throw new Error(en_1.lib.migrate.errors.migrationFailed, {
208
+ cause: error,
209
+ });
210
+ }
211
+ if (pollResponse.status !== Migration_1.MIGRATION_STATUS.SUCCESS) {
212
+ throw new Error(en_1.lib.migrate.errors.migrationFailed);
177
213
  }
214
+ logger_1.logger.debug(util_1.default.inspect(pollResponse, { depth: null }));
178
215
  if (pollResponse.status === Migration_1.MIGRATION_STATUS.SUCCESS) {
179
216
  SpinniesManager_1.default.succeed('finishingMigration', {
180
- text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.migrationComplete`),
217
+ text: en_1.lib.migrate.spinners.migrationComplete,
181
218
  });
182
- return pollResponse.buildId;
183
- }
184
- else {
185
- SpinniesManager_1.default.fail('finishingMigration', {
186
- text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.migrationFailed`),
187
- });
188
- if (pollResponse.status === Migration_1.MIGRATION_STATUS.FAILURE) {
189
- logger_1.logger.error(pollResponse.componentErrorDetails);
190
- throw new Error(pollResponse.projectErrorsDetail);
191
- }
192
- throw new Error((0, lang_1.i18n)('commands.project.subcommands.migrateApp.errors.migrationFailed'));
193
219
  }
220
+ return pollResponse.buildId;
194
221
  }
195
- async function downloadProjectFiles(derivedAccountId, projectName, buildId, projectDest) {
222
+ async function downloadProjectFiles(derivedAccountId, projectName, buildId, projectDest, projectConfig) {
196
223
  try {
197
224
  SpinniesManager_1.default.add('fetchingMigratedProject', {
198
- text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.downloadingProjectContents`),
225
+ text: en_1.lib.migrate.spinners.downloadingProjectContents,
199
226
  });
200
227
  const { data: zippedProject } = await (0, projects_2.downloadProject)(derivedAccountId, projectName, buildId);
201
- const absoluteDestPath = projectDest
202
- ? path_1.default.resolve((0, path_2.getCwd)(), projectDest)
203
- : (0, path_2.getCwd)();
228
+ let absoluteDestPath;
229
+ if (projectConfig?.projectConfig && projectConfig?.projectDir) {
230
+ const { projectDir } = projectConfig;
231
+ absoluteDestPath = projectDir;
232
+ const { srcDir } = projectConfig.projectConfig;
233
+ const archiveDest = path_1.default.join(projectDir, 'archive');
234
+ // Move the existing source directory to archive
235
+ fs_1.default.renameSync(path_1.default.join(projectDir, srcDir), archiveDest);
236
+ }
237
+ else {
238
+ absoluteDestPath = projectDest
239
+ ? path_1.default.resolve((0, path_2.getCwd)(), projectDest)
240
+ : (0, path_2.getCwd)();
241
+ }
204
242
  await (0, archive_1.extractZipArchive)(zippedProject, (0, path_2.sanitizeFileName)(projectName), absoluteDestPath, {
205
243
  includesRootDir: true,
206
244
  hideLogs: true,
207
245
  });
208
246
  SpinniesManager_1.default.succeed('fetchingMigratedProject', {
209
- text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.downloadingProjectContentsComplete`),
247
+ text: en_1.lib.migrate.spinners.downloadingProjectContentsComplete,
210
248
  });
211
249
  logger_1.logger.success(`Saved ${projectName} to ${projectDest}`);
212
250
  }
213
251
  catch (error) {
214
252
  SpinniesManager_1.default.fail('fetchingMigratedProject', {
215
- text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.downloadingProjectContentsFailed`),
253
+ text: en_1.lib.migrate.spinners.downloadingProjectContentsFailed,
216
254
  });
217
255
  throw error;
218
256
  }
219
257
  }
220
- async function migrateApp2025_2(derivedAccountId, options) {
258
+ async function migrateApp2025_2(derivedAccountId, options, projectConfig) {
221
259
  SpinniesManager_1.default.init();
222
- const { appIdToMigrate, projectName, projectDest } = await handleMigrationSetup(derivedAccountId, options);
260
+ const ungatedForUnifiedApps = await (0, hasFeature_1.hasFeature)(derivedAccountId, 'Developers:UnifiedApps:PrivateBeta');
261
+ if (!ungatedForUnifiedApps) {
262
+ throw new Error(en_1.lib.migrate.errors.notUngatedForUnifiedApps((0, ui_1.uiAccountDescription)(derivedAccountId)));
263
+ }
264
+ if (projectConfig) {
265
+ if (!projectConfig?.projectConfig || !projectConfig?.projectDir) {
266
+ throw new Error(en_1.lib.migrate.errors.project.invalidConfig);
267
+ }
268
+ const { projectExists } = await (0, projects_3.ensureProjectExists)(derivedAccountId, projectConfig.projectConfig.name, { allowCreate: false, noLogs: true });
269
+ if (!projectExists) {
270
+ throw new Error(en_1.lib.migrate.errors.project.doesNotExist);
271
+ }
272
+ }
273
+ const { appIdToMigrate, projectName, projectDest } = await handleMigrationSetup(derivedAccountId, options, projectConfig);
223
274
  if (!appIdToMigrate || !projectName || !projectDest) {
224
275
  return;
225
276
  }
@@ -228,15 +279,12 @@ async function migrateApp2025_2(derivedAccountId, options) {
228
279
  return;
229
280
  }
230
281
  const { migrationId, uidMap } = migrationInProgress;
231
- const buildId = await finalizeMigration(derivedAccountId, migrationId, uidMap, projectName);
232
- await downloadProjectFiles(derivedAccountId, projectName, buildId, projectDest);
282
+ const buildId = await finalizeMigration(derivedAccountId, migrationId, uidMap, projectConfig?.projectConfig?.name || projectName);
283
+ await downloadProjectFiles(derivedAccountId, projectName, buildId, projectDest, projectConfig);
233
284
  }
234
- function logInvalidAccountError(i18nKey) {
285
+ function logInvalidAccountError() {
235
286
  (0, ui_1.uiLine)();
236
- logger_1.logger.error((0, lang_1.i18n)(`${i18nKey}.errors.invalidAccountTypeTitle`));
237
- logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.errors.invalidAccountTypeDescription`, {
238
- useCommand: (0, ui_1.uiCommandReference)('hs accounts use'),
239
- authCommand: (0, ui_1.uiCommandReference)('hs auth'),
240
- }));
287
+ logger_1.logger.error(en_1.lib.migrate.errors.invalidAccountTypeTitle);
288
+ logger_1.logger.log(en_1.lib.migrate.errors.invalidAccountTypeDescription((0, ui_1.uiCommandReference)('hs account use'), (0, ui_1.uiCommandReference)('hs auth')));
241
289
  (0, ui_1.uiLine)();
242
290
  }
@@ -1,4 +1,4 @@
1
1
  import { CLIAccount } from '@hubspot/local-dev-lib/types/Accounts';
2
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>;
3
+ import { MigrateAppArgs } from './migrate';
4
+ export declare function migrateApp2023_2(derivedAccountId: number, options: ArgumentsCamelCase<MigrateAppArgs>, accountConfig: CLIAccount): Promise<void>;
@@ -28,16 +28,18 @@ const migrate_1 = require("./migrate");
28
28
  async function migrateApp2023_2(derivedAccountId, options, accountConfig) {
29
29
  const accountName = (0, ui_1.uiAccountDescription)(derivedAccountId);
30
30
  if (!(0, accountTypes_1.isAppDeveloperAccount)(accountConfig)) {
31
- (0, migrate_1.logInvalidAccountError)('commands.project.subcommands.migrateApp');
31
+ (0, migrate_1.logInvalidAccountError)();
32
32
  process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
33
33
  }
34
- const { appId } = 'appId' in options
35
- ? options
36
- : await (0, selectPublicAppPrompt_1.selectPublicAppPrompt)({
34
+ let appId = options.appId;
35
+ if (!appId) {
36
+ const { appId: selectAppId } = await (0, selectPublicAppPrompt_1.selectPublicAppPrompt)({
37
37
  accountId: derivedAccountId,
38
38
  accountName,
39
39
  isMigratingApp: true,
40
40
  });
41
+ appId = selectAppId;
42
+ }
41
43
  try {
42
44
  const { data: selectedApp } = await (0, appsDev_1.fetchPublicAppMetadata)(appId, derivedAccountId);
43
45
  // preventProjectMigrations returns true if we have not added app to allowlist config.
@@ -2,10 +2,11 @@ import { Project } from '@hubspot/local-dev-lib/types/Project';
2
2
  import { ProjectConfig } from '../../types/Projects';
3
3
  export declare function writeProjectConfig(configPath: string, config: ProjectConfig): boolean;
4
4
  export declare function getIsInProject(dir?: string): boolean;
5
- export declare function getProjectConfig(dir?: string): Promise<{
5
+ export interface LoadedProjectConfig {
6
6
  projectDir: string | null;
7
7
  projectConfig: ProjectConfig | null;
8
- }>;
8
+ }
9
+ export declare function getProjectConfig(dir?: string): Promise<LoadedProjectConfig>;
9
10
  export declare function validateProjectConfig(projectConfig: ProjectConfig | null, projectDir: string | null): asserts projectConfig is ProjectConfig;
10
11
  export declare function ensureProjectExists(accountId: number, projectName: string, { forceCreate, allowCreate, noLogs, withPolling, uploadCommand, }?: {
11
12
  forceCreate?: boolean | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubspot/cli",
3
- "version": "7.4.1",
3
+ "version": "7.4.2-beta.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",
package/types/Yargs.d.ts CHANGED
@@ -27,13 +27,3 @@ export type ProjectDevArgs = CommonArgs & ConfigArgs & EnvironmentArgs;
27
27
  export type TestingArgs = {
28
28
  qa?: boolean;
29
29
  };
30
- export type MigrateAppOptions = CommonArgs & AccountArgs & EnvironmentArgs & ConfigArgs & {
31
- name: string;
32
- dest: string;
33
- appId: number;
34
- platformVersion: string;
35
- };
36
- export type CloneAppArgs = ConfigArgs & EnvironmentArgs & AccountArgs & CommonArgs & {
37
- dest: string;
38
- appId: number;
39
- };