@hubspot/cli 7.3.0 → 7.4.0-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.
- package/bin/cli.js +2 -0
- package/commands/app/migrate.d.ts +7 -0
- package/commands/app/migrate.js +94 -0
- package/commands/app.d.ts +6 -0
- package/commands/app.js +23 -0
- package/commands/project/cloneApp.d.ts +9 -1
- package/commands/project/cloneApp.js +91 -76
- package/commands/project/create.js +0 -1
- package/commands/project/migrateApp.d.ts +9 -1
- package/commands/project/migrateApp.js +43 -170
- package/lang/en.js +1 -6
- package/lang/en.lyaml +32 -4
- package/lib/DevServerManagerV2.d.ts +2 -1
- package/lib/DevServerManagerV2.js +2 -1
- package/lib/LocalDevManagerV2.js +15 -10
- package/lib/app/migrate.d.ts +7 -0
- package/lib/app/migrate.js +345 -0
- package/lib/polling.d.ts +4 -0
- package/lib/polling.js +3 -3
- package/lib/projects/structure.d.ts +2 -1
- package/lib/projects/structure.js +4 -0
- package/lib/prompts/promptUtils.d.ts +6 -4
- package/lib/prompts/promptUtils.js +3 -1
- package/lib/ui/index.d.ts +2 -2
- package/lib/ui/index.js +6 -5
- package/package.json +3 -3
- package/types/ProjectComponents.d.ts +15 -0
- package/types/Prompts.d.ts +2 -2
- package/types/Yargs.d.ts +10 -0
|
@@ -0,0 +1,345 @@
|
|
|
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.downloadProjectFiles = downloadProjectFiles;
|
|
7
|
+
exports.migrateApp2025_2 = migrateApp2025_2;
|
|
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
|
+
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
|
+
const path_1 = __importDefault(require("path"));
|
|
27
|
+
const path_2 = require("@hubspot/local-dev-lib/path");
|
|
28
|
+
const urls_1 = require("@hubspot/local-dev-lib/urls");
|
|
29
|
+
const archive_1 = require("@hubspot/local-dev-lib/archive");
|
|
30
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
31
|
+
const project_parsing_lib_1 = require("@hubspot/project-parsing-lib");
|
|
32
|
+
const projects_3 = require("@hubspot/local-dev-lib/constants/projects");
|
|
33
|
+
const transform_1 = require("@hubspot/project-parsing-lib/src/lib/transform");
|
|
34
|
+
function getUnmigratableReason(reasonCode) {
|
|
35
|
+
switch (reasonCode) {
|
|
36
|
+
case projects_3.UNMIGRATABLE_REASONS.UP_TO_DATE:
|
|
37
|
+
return (0, lang_1.i18n)('commands.project.subcommands.migrateApp.unmigratableReasons.upToDate');
|
|
38
|
+
case projects_3.UNMIGRATABLE_REASONS.IS_A_PRIVATE_APP:
|
|
39
|
+
return (0, lang_1.i18n)('commands.project.subcommands.migrateApp.unmigratableReasons.isPrivateApp');
|
|
40
|
+
case projects_3.UNMIGRATABLE_REASONS.LISTED_IN_MARKETPLACE:
|
|
41
|
+
return (0, lang_1.i18n)('commands.project.subcommands.migrateApp.unmigratableReasons.listedInMarketplace');
|
|
42
|
+
default:
|
|
43
|
+
return (0, lang_1.i18n)('commands.project.subcommands.migrateApp.unmigratableReasons.generic', {
|
|
44
|
+
reasonCode,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function handleMigrationSetup(derivedAccountId, options) {
|
|
49
|
+
const { name, dest, appId } = options;
|
|
50
|
+
const { data } = await (0, projects_2.listAppsForMigration)(derivedAccountId);
|
|
51
|
+
const { migratableApps, unmigratableApps } = data;
|
|
52
|
+
const allApps = [...migratableApps, ...unmigratableApps].filter(app => !app.projectName);
|
|
53
|
+
if (allApps.length === 0) {
|
|
54
|
+
throw new Error((0, lang_1.i18n)(`commands.project.subcommands.migrateApp.errors.noApps`, {
|
|
55
|
+
accountId: derivedAccountId,
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
if (migratableApps.length === 0) {
|
|
59
|
+
const reasons = unmigratableApps.map(app => `${chalk_1.default.bold(app.appName)}: ${getUnmigratableReason(app.unmigratableReason)}`);
|
|
60
|
+
throw new Error(`${(0, lang_1.i18n)(`commands.project.subcommands.migrateApp.errors.noAppsEligible`, {
|
|
61
|
+
accountId: derivedAccountId,
|
|
62
|
+
})} \n - ${reasons.join('\n - ')}`);
|
|
63
|
+
}
|
|
64
|
+
if (appId &&
|
|
65
|
+
!allApps.some(app => {
|
|
66
|
+
return app.appId === appId;
|
|
67
|
+
})) {
|
|
68
|
+
throw new Error((0, lang_1.i18n)('commands.project.subcommands.migrateApp.prompt.chooseApp', {
|
|
69
|
+
appId,
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
const appChoices = allApps.map(app => ({
|
|
73
|
+
name: app.isMigratable
|
|
74
|
+
? app.appName
|
|
75
|
+
: `[${chalk_1.default.yellow('DISABLED')}] ${app.appName} `,
|
|
76
|
+
value: app,
|
|
77
|
+
disabled: app.isMigratable
|
|
78
|
+
? false
|
|
79
|
+
: getUnmigratableReason(app.unmigratableReason),
|
|
80
|
+
}));
|
|
81
|
+
let appIdToMigrate = appId;
|
|
82
|
+
if (!appIdToMigrate) {
|
|
83
|
+
const { appId: selectedAppId } = await (0, promptUtils_1.listPrompt)((0, lang_1.i18n)('commands.project.subcommands.migrateApp.prompt.chooseApp'), {
|
|
84
|
+
choices: appChoices,
|
|
85
|
+
});
|
|
86
|
+
appIdToMigrate = selectedAppId;
|
|
87
|
+
}
|
|
88
|
+
const selectedApp = allApps.find(app => app.appId === appIdToMigrate);
|
|
89
|
+
const migratableComponents = [];
|
|
90
|
+
const unmigratableComponents = [];
|
|
91
|
+
selectedApp?.migrationComponents.forEach(component => {
|
|
92
|
+
if (component.isSupported) {
|
|
93
|
+
migratableComponents.push((0, transform_1.mapToUserFacingType)(component.componentType));
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
unmigratableComponents.push((0, transform_1.mapToUserFacingType)(component.componentType));
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
if (migratableComponents.length !== 0) {
|
|
100
|
+
logger_1.logger.log((0, lang_1.i18n)('commands.project.subcommands.migrateApp.componentsToBeMigrated', {
|
|
101
|
+
components: `\n - ${migratableComponents.join('\n - ')}`,
|
|
102
|
+
}));
|
|
103
|
+
}
|
|
104
|
+
if (unmigratableComponents.length !== 0) {
|
|
105
|
+
logger_1.logger.log((0, lang_1.i18n)('commands.project.subcommands.migrateApp.componentsThatWillNotBeMigrated', {
|
|
106
|
+
components: `\n - ${unmigratableComponents.join('\n - ')}`,
|
|
107
|
+
}));
|
|
108
|
+
}
|
|
109
|
+
logger_1.logger.log();
|
|
110
|
+
const proceed = await (0, promptUtils_1.confirmPrompt)((0, lang_1.i18n)('commands.project.subcommands.migrateApp.prompt.proceed'));
|
|
111
|
+
if (!proceed) {
|
|
112
|
+
return {};
|
|
113
|
+
}
|
|
114
|
+
const projectName = name ||
|
|
115
|
+
(await (0, promptUtils_1.inputPrompt)((0, lang_1.i18n)('commands.project.subcommands.migrateApp.prompt.inputName')));
|
|
116
|
+
const { projectExists } = await (0, projects_1.ensureProjectExists)(derivedAccountId, projectName, { forceCreate: false, allowCreate: false, noLogs: true });
|
|
117
|
+
if (projectExists) {
|
|
118
|
+
throw new Error((0, lang_1.i18n)('commands.project.subcommands.migrateApp.errors.projectAlreadyExists', {
|
|
119
|
+
projectName,
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
const projectDest = dest ||
|
|
123
|
+
(await (0, promptUtils_1.inputPrompt)((0, lang_1.i18n)('commands.project.subcommands.migrateApp.prompt.inputDest'), {
|
|
124
|
+
defaultAnswer: path_1.default.resolve((0, path_2.getCwd)(), (0, path_2.sanitizeFileName)(projectName)),
|
|
125
|
+
}));
|
|
126
|
+
return { appIdToMigrate, projectName, projectDest };
|
|
127
|
+
}
|
|
128
|
+
async function beginMigration(derivedAccountId, appId, platformVersion) {
|
|
129
|
+
SpinniesManager_1.default.add('beginningMigration', {
|
|
130
|
+
text: (0, lang_1.i18n)('commands.project.subcommands.migrateApp.spinners.beginningMigration'),
|
|
131
|
+
});
|
|
132
|
+
const uidMap = {};
|
|
133
|
+
const { data } = await (0, projects_2.initializeMigration)(derivedAccountId, appId, platformVersion);
|
|
134
|
+
const { migrationId } = data;
|
|
135
|
+
const pollResponse = await pollMigrationStatus(derivedAccountId, migrationId, ['INPUT_REQUIRED']);
|
|
136
|
+
if (pollResponse.status !== 'INPUT_REQUIRED') {
|
|
137
|
+
SpinniesManager_1.default.fail('beginningMigration', {
|
|
138
|
+
text: (0, lang_1.i18n)('commands.project.subcommands.migrateApp.spinners.unableToStartMigration'),
|
|
139
|
+
});
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const { componentsRequiringUids } = pollResponse;
|
|
143
|
+
SpinniesManager_1.default.succeed('beginningMigration', {
|
|
144
|
+
text: (0, lang_1.i18n)('commands.project.subcommands.migrateApp.spinners.migrationStarted'),
|
|
145
|
+
});
|
|
146
|
+
if (Object.values(componentsRequiringUids).length !== 0) {
|
|
147
|
+
for (const [componentId, component] of Object.entries(componentsRequiringUids)) {
|
|
148
|
+
uidMap[componentId] = await (0, promptUtils_1.inputPrompt)((0, lang_1.i18n)('commands.project.subcommands.migrateApp.prompt.uidForComponent', {
|
|
149
|
+
componentName: component.componentHint || component.componentType,
|
|
150
|
+
}), {
|
|
151
|
+
validate: (uid) => {
|
|
152
|
+
const result = (0, project_parsing_lib_1.validateUid)(uid);
|
|
153
|
+
return result === undefined ? true : result;
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return { migrationId, uidMap };
|
|
159
|
+
}
|
|
160
|
+
async function pollMigrationStatus(derivedAccountId, migrationId, successStates = []) {
|
|
161
|
+
return (0, polling_1.poll)(() => (0, projects_2.checkMigrationStatusV2)(derivedAccountId, migrationId), {
|
|
162
|
+
successStates: [...successStates],
|
|
163
|
+
errorStates: [...polling_1.DEFAULT_POLLING_STATUS_LOOKUP.errorStates],
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
async function finalizeMigration(derivedAccountId, migrationId, uidMap, projectName) {
|
|
167
|
+
let buildId;
|
|
168
|
+
try {
|
|
169
|
+
SpinniesManager_1.default.add('finishingMigration', {
|
|
170
|
+
text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.finishingMigration`),
|
|
171
|
+
});
|
|
172
|
+
await (0, projects_2.continueMigration)(derivedAccountId, migrationId, uidMap, projectName);
|
|
173
|
+
const pollResponse = await pollMigrationStatus(derivedAccountId, migrationId, ['SUCCESS']);
|
|
174
|
+
if (pollResponse.status === 'SUCCESS') {
|
|
175
|
+
buildId = pollResponse.buildId;
|
|
176
|
+
SpinniesManager_1.default.succeed('finishingMigration', {
|
|
177
|
+
text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.migrationComplete`),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
SpinniesManager_1.default.fail('finishingMigration', {
|
|
182
|
+
text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.migrationFailed`),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
return buildId;
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
SpinniesManager_1.default.fail('finishingMigration', {
|
|
189
|
+
text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.migrationFailed`),
|
|
190
|
+
});
|
|
191
|
+
throw error;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
async function downloadProjectFiles(derivedAccountId, projectName, buildId, projectDest) {
|
|
195
|
+
try {
|
|
196
|
+
SpinniesManager_1.default.add('fetchingMigratedProject', {
|
|
197
|
+
text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.downloadingProjectContents`),
|
|
198
|
+
});
|
|
199
|
+
const { data: zippedProject } = await (0, projects_2.downloadProject)(derivedAccountId, projectName, buildId);
|
|
200
|
+
const absoluteDestPath = projectDest
|
|
201
|
+
? path_1.default.resolve((0, path_2.getCwd)(), projectDest)
|
|
202
|
+
: (0, path_2.getCwd)();
|
|
203
|
+
await (0, archive_1.extractZipArchive)(zippedProject, (0, path_2.sanitizeFileName)(projectName), absoluteDestPath, {
|
|
204
|
+
includesRootDir: true,
|
|
205
|
+
hideLogs: false,
|
|
206
|
+
});
|
|
207
|
+
SpinniesManager_1.default.succeed('fetchingMigratedProject', {
|
|
208
|
+
text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.downloadingProjectContentsComplete`),
|
|
209
|
+
});
|
|
210
|
+
logger_1.logger.success(`Saved ${projectName} to ${projectDest}`);
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
SpinniesManager_1.default.fail('fetchingMigratedProject', {
|
|
214
|
+
text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.downloadingProjectContentsFailed`),
|
|
215
|
+
});
|
|
216
|
+
throw error;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
async function migrateApp2025_2(derivedAccountId, options) {
|
|
220
|
+
SpinniesManager_1.default.init();
|
|
221
|
+
const { appIdToMigrate, projectName, projectDest } = await handleMigrationSetup(derivedAccountId, options);
|
|
222
|
+
if (!appIdToMigrate || !projectName || !projectDest) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
const migrationInProgress = await beginMigration(derivedAccountId, appIdToMigrate, options.platformVersion);
|
|
226
|
+
if (!migrationInProgress) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const { migrationId, uidMap } = migrationInProgress;
|
|
230
|
+
const buildId = await finalizeMigration(derivedAccountId, migrationId, uidMap, projectName);
|
|
231
|
+
if (!buildId) {
|
|
232
|
+
throw new Error('Migration Failed');
|
|
233
|
+
}
|
|
234
|
+
await downloadProjectFiles(derivedAccountId, projectName, buildId, projectDest);
|
|
235
|
+
}
|
|
236
|
+
function logInvalidAccountError(i18nKey) {
|
|
237
|
+
(0, ui_1.uiLine)();
|
|
238
|
+
logger_1.logger.error((0, lang_1.i18n)(`${i18nKey}.errors.invalidAccountTypeTitle`));
|
|
239
|
+
logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.errors.invalidAccountTypeDescription`, {
|
|
240
|
+
useCommand: (0, ui_1.uiCommandReference)('hs accounts use'),
|
|
241
|
+
authCommand: (0, ui_1.uiCommandReference)('hs auth'),
|
|
242
|
+
}));
|
|
243
|
+
(0, ui_1.uiLine)();
|
|
244
|
+
}
|
|
245
|
+
async function migrateApp2023_2(derivedAccountId, options, accountConfig) {
|
|
246
|
+
const i18nKey = 'commands.project.subcommands.migrateApp';
|
|
247
|
+
const accountName = (0, ui_1.uiAccountDescription)(derivedAccountId);
|
|
248
|
+
if (!(0, accountTypes_1.isAppDeveloperAccount)(accountConfig)) {
|
|
249
|
+
logInvalidAccountError(i18nKey);
|
|
250
|
+
process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
251
|
+
}
|
|
252
|
+
const { appId } = 'appId' in options
|
|
253
|
+
? options
|
|
254
|
+
: await (0, selectPublicAppPrompt_1.selectPublicAppPrompt)({
|
|
255
|
+
accountId: derivedAccountId,
|
|
256
|
+
accountName,
|
|
257
|
+
isMigratingApp: true,
|
|
258
|
+
});
|
|
259
|
+
try {
|
|
260
|
+
const { data: selectedApp } = await (0, appsDev_1.fetchPublicAppMetadata)(appId, derivedAccountId);
|
|
261
|
+
// preventProjectMigrations returns true if we have not added app to allowlist config.
|
|
262
|
+
// listingInfo will only exist for marketplace apps
|
|
263
|
+
const preventProjectMigrations = selectedApp.preventProjectMigrations;
|
|
264
|
+
const listingInfo = selectedApp.listingInfo;
|
|
265
|
+
if (preventProjectMigrations && listingInfo) {
|
|
266
|
+
logger_1.logger.error((0, lang_1.i18n)(`${i18nKey}.errors.invalidApp`, { appId }));
|
|
267
|
+
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
(0, errorHandlers_1.logError)(error, new errorHandlers_1.ApiErrorContext({ accountId: derivedAccountId }));
|
|
272
|
+
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
273
|
+
}
|
|
274
|
+
const createProjectPromptResponse = await (0, createProjectPrompt_1.createProjectPrompt)(options);
|
|
275
|
+
const { name: projectName, dest: projectDest } = createProjectPromptResponse;
|
|
276
|
+
const { projectExists } = await (0, projects_1.ensureProjectExists)(derivedAccountId, projectName, {
|
|
277
|
+
allowCreate: false,
|
|
278
|
+
noLogs: true,
|
|
279
|
+
});
|
|
280
|
+
if (projectExists) {
|
|
281
|
+
throw new Error((0, lang_1.i18n)(`${i18nKey}.errors.projectAlreadyExists`, {
|
|
282
|
+
projectName,
|
|
283
|
+
}));
|
|
284
|
+
}
|
|
285
|
+
await (0, usageTracking_1.trackCommandMetadataUsage)('migrate-app', { step: 'STARTED' }, derivedAccountId);
|
|
286
|
+
logger_1.logger.log('');
|
|
287
|
+
(0, ui_1.uiLine)();
|
|
288
|
+
logger_1.logger.warn(`${(0, lang_1.i18n)(`${i18nKey}.warning.title`)}\n`);
|
|
289
|
+
logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.warning.projectConversion`));
|
|
290
|
+
logger_1.logger.log(`${(0, lang_1.i18n)(`${i18nKey}.warning.appConfig`)}\n`);
|
|
291
|
+
logger_1.logger.log(`${(0, lang_1.i18n)(`${i18nKey}.warning.buildAndDeploy`)}\n`);
|
|
292
|
+
logger_1.logger.log(`${(0, lang_1.i18n)(`${i18nKey}.warning.existingApps`)}\n`);
|
|
293
|
+
logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.warning.copyApp`));
|
|
294
|
+
(0, ui_1.uiLine)();
|
|
295
|
+
const { shouldCreateApp } = await (0, promptUtils_1.promptUser)({
|
|
296
|
+
name: 'shouldCreateApp',
|
|
297
|
+
type: 'confirm',
|
|
298
|
+
message: (0, lang_1.i18n)(`${i18nKey}.createAppPrompt`),
|
|
299
|
+
});
|
|
300
|
+
process.stdin.resume();
|
|
301
|
+
if (!shouldCreateApp) {
|
|
302
|
+
process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
303
|
+
}
|
|
304
|
+
try {
|
|
305
|
+
SpinniesManager_1.default.init();
|
|
306
|
+
SpinniesManager_1.default.add('migrateApp', {
|
|
307
|
+
text: (0, lang_1.i18n)(`${i18nKey}.migrationStatus.inProgress`),
|
|
308
|
+
});
|
|
309
|
+
(0, process_1.handleKeypress)(async (key) => {
|
|
310
|
+
if ((key.ctrl && key.name === 'c') || key.name === 'q') {
|
|
311
|
+
SpinniesManager_1.default.remove('migrateApp');
|
|
312
|
+
logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.migrationInterrupted`));
|
|
313
|
+
process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
const { data: migrateResponse } = await (0, projects_2.migrateApp)(derivedAccountId, appId, projectName);
|
|
317
|
+
const { id } = migrateResponse;
|
|
318
|
+
const pollResponse = await (0, polling_1.poll)(() => (0, projects_2.checkMigrationStatus)(derivedAccountId, id));
|
|
319
|
+
const { status, project } = pollResponse;
|
|
320
|
+
if (status === 'SUCCESS') {
|
|
321
|
+
const absoluteDestPath = path_1.default.resolve((0, path_2.getCwd)(), projectDest);
|
|
322
|
+
const { env } = accountConfig;
|
|
323
|
+
const baseUrl = (0, urls_1.getHubSpotWebsiteOrigin)(env);
|
|
324
|
+
const { data: zippedProject } = await (0, projects_2.downloadProject)(derivedAccountId, projectName, 1);
|
|
325
|
+
await (0, archive_1.extractZipArchive)(zippedProject, (0, path_2.sanitizeFileName)(projectName), path_1.default.resolve(absoluteDestPath), { includesRootDir: true, hideLogs: true });
|
|
326
|
+
SpinniesManager_1.default.succeed('migrateApp', {
|
|
327
|
+
text: (0, lang_1.i18n)(`${i18nKey}.migrationStatus.done`),
|
|
328
|
+
succeedColor: 'white',
|
|
329
|
+
});
|
|
330
|
+
logger_1.logger.log('');
|
|
331
|
+
(0, ui_1.uiLine)();
|
|
332
|
+
logger_1.logger.success((0, lang_1.i18n)(`${i18nKey}.migrationStatus.success`));
|
|
333
|
+
logger_1.logger.log('');
|
|
334
|
+
logger_1.logger.log((0, ui_1.uiLink)((0, lang_1.i18n)(`${i18nKey}.projectDetailsLink`), `${baseUrl}/developer-projects/${derivedAccountId}/project/${encodeURIComponent(project.name)}`));
|
|
335
|
+
process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
SpinniesManager_1.default.fail('migrateApp', {
|
|
340
|
+
text: (0, lang_1.i18n)(`${i18nKey}.migrationStatus.failure`),
|
|
341
|
+
failColor: 'white',
|
|
342
|
+
});
|
|
343
|
+
throw error;
|
|
344
|
+
}
|
|
345
|
+
}
|
package/lib/polling.d.ts
CHANGED
|
@@ -6,6 +6,10 @@ export declare const DEFAULT_POLLING_STATES: {
|
|
|
6
6
|
readonly REVERTED: "REVERTED";
|
|
7
7
|
readonly FAILURE: "FAILURE";
|
|
8
8
|
};
|
|
9
|
+
export declare const DEFAULT_POLLING_STATUS_LOOKUP: {
|
|
10
|
+
successStates: "SUCCESS"[];
|
|
11
|
+
errorStates: ("FAILURE" | "ERROR" | "REVERTED")[];
|
|
12
|
+
};
|
|
9
13
|
type GenericPollingResponse = {
|
|
10
14
|
status: string;
|
|
11
15
|
};
|
package/lib/polling.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_POLLING_STATES = void 0;
|
|
3
|
+
exports.DEFAULT_POLLING_STATUS_LOOKUP = exports.DEFAULT_POLLING_STATES = void 0;
|
|
4
4
|
exports.poll = poll;
|
|
5
5
|
const constants_1 = require("./constants");
|
|
6
6
|
exports.DEFAULT_POLLING_STATES = {
|
|
@@ -10,7 +10,7 @@ exports.DEFAULT_POLLING_STATES = {
|
|
|
10
10
|
REVERTED: 'REVERTED',
|
|
11
11
|
FAILURE: 'FAILURE',
|
|
12
12
|
};
|
|
13
|
-
|
|
13
|
+
exports.DEFAULT_POLLING_STATUS_LOOKUP = {
|
|
14
14
|
successStates: [exports.DEFAULT_POLLING_STATES.SUCCESS],
|
|
15
15
|
errorStates: [
|
|
16
16
|
exports.DEFAULT_POLLING_STATES.ERROR,
|
|
@@ -18,7 +18,7 @@ const DEFAULT_POLLING_STATUS_LOOKUP = {
|
|
|
18
18
|
exports.DEFAULT_POLLING_STATES.FAILURE,
|
|
19
19
|
],
|
|
20
20
|
};
|
|
21
|
-
function poll(callback, statusLookup = DEFAULT_POLLING_STATUS_LOOKUP) {
|
|
21
|
+
function poll(callback, statusLookup = exports.DEFAULT_POLLING_STATUS_LOOKUP) {
|
|
22
22
|
return new Promise((resolve, reject) => {
|
|
23
23
|
const pollInterval = setInterval(async () => {
|
|
24
24
|
try {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ComponentTypes, Component, GenericComponentConfig, PublicAppComponentConfig, PrivateAppComponentConfig, AppCardComponentConfig } from '../../types/Projects';
|
|
2
2
|
import { IntermediateRepresentationNodeLocalDev } from '@hubspot/project-parsing-lib/src/lib/types';
|
|
3
|
-
import { AppIRNode } from '../../types/ProjectComponents';
|
|
3
|
+
import { AppIRNode, CardIRNode } from '../../types/ProjectComponents';
|
|
4
4
|
export declare const CONFIG_FILES: {
|
|
5
5
|
[k in ComponentTypes]: string;
|
|
6
6
|
};
|
|
@@ -16,3 +16,4 @@ export declare function getComponentUid(component?: Component | null): string |
|
|
|
16
16
|
export declare function componentIsApp(component?: Component | null): component is Component<PublicAppComponentConfig | PrivateAppComponentConfig>;
|
|
17
17
|
export declare function componentIsPublicApp(component?: Component | null): component is Component<PublicAppComponentConfig>;
|
|
18
18
|
export declare function isAppIRNode(component: IntermediateRepresentationNodeLocalDev): component is AppIRNode;
|
|
19
|
+
export declare function isCardIRNode(component: IntermediateRepresentationNodeLocalDev): component is CardIRNode;
|
|
@@ -44,6 +44,7 @@ exports.getComponentUid = getComponentUid;
|
|
|
44
44
|
exports.componentIsApp = componentIsApp;
|
|
45
45
|
exports.componentIsPublicApp = componentIsPublicApp;
|
|
46
46
|
exports.isAppIRNode = isAppIRNode;
|
|
47
|
+
exports.isCardIRNode = isCardIRNode;
|
|
47
48
|
const fs = __importStar(require("fs"));
|
|
48
49
|
const path = __importStar(require("path"));
|
|
49
50
|
const fs_1 = require("@hubspot/local-dev-lib/fs");
|
|
@@ -174,3 +175,6 @@ function componentIsPublicApp(component) {
|
|
|
174
175
|
function isAppIRNode(component) {
|
|
175
176
|
return component.componentType === constants_1.IR_COMPONENT_TYPES.APPLICATION;
|
|
176
177
|
}
|
|
178
|
+
function isCardIRNode(component) {
|
|
179
|
+
return component.componentType === constants_1.IR_COMPONENT_TYPES.CARD;
|
|
180
|
+
}
|
|
@@ -4,10 +4,12 @@ export declare function confirmPrompt(message: string, options?: {
|
|
|
4
4
|
defaultAnswer?: boolean;
|
|
5
5
|
when?: PromptWhen;
|
|
6
6
|
}): Promise<boolean>;
|
|
7
|
-
export declare function listPrompt(message: string, { choices, when, }: {
|
|
8
|
-
choices: PromptChoices
|
|
7
|
+
export declare function listPrompt<T = string>(message: string, { choices, when, }: {
|
|
8
|
+
choices: PromptChoices<T>;
|
|
9
9
|
when?: PromptWhen;
|
|
10
|
-
}): Promise<
|
|
11
|
-
export declare function inputPrompt(message: string, { when, }?: {
|
|
10
|
+
}): Promise<T>;
|
|
11
|
+
export declare function inputPrompt(message: string, { when, validate, defaultAnswer, }?: {
|
|
12
12
|
when?: boolean | (() => boolean);
|
|
13
|
+
validate?: (input: string) => boolean | string;
|
|
14
|
+
defaultAnswer?: string;
|
|
13
15
|
}): Promise<string>;
|
|
@@ -34,13 +34,15 @@ async function listPrompt(message, { choices, when, }) {
|
|
|
34
34
|
]);
|
|
35
35
|
return choice;
|
|
36
36
|
}
|
|
37
|
-
async function inputPrompt(message, { when, } = {}) {
|
|
37
|
+
async function inputPrompt(message, { when, validate, defaultAnswer, } = {}) {
|
|
38
38
|
const { input } = await promptUser([
|
|
39
39
|
{
|
|
40
40
|
name: 'input',
|
|
41
41
|
type: 'input',
|
|
42
|
+
default: defaultAnswer,
|
|
42
43
|
message,
|
|
43
44
|
when,
|
|
45
|
+
validate,
|
|
44
46
|
},
|
|
45
47
|
]);
|
|
46
48
|
return input;
|
package/lib/ui/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export declare function uiCommandReference(command: string, withQuotes?: boolean
|
|
|
11
11
|
export declare function uiFeatureHighlight(features: string[], title?: string): void;
|
|
12
12
|
export declare function uiBetaTag(message: string, log?: true): undefined;
|
|
13
13
|
export declare function uiBetaTag(message: string, log: false): string;
|
|
14
|
-
export declare function uiDeprecatedTag(message: string):
|
|
14
|
+
export declare function uiDeprecatedTag(message: string, log?: boolean): string | undefined;
|
|
15
15
|
export declare function uiCommandDisabledBanner(command: string, url?: string, message?: string): void;
|
|
16
|
-
export declare function uiDeprecatedDescription(message: string, command: string, url?: string):
|
|
16
|
+
export declare function uiDeprecatedDescription(message: string, command: string, url?: string): string | undefined;
|
|
17
17
|
export declare function uiDeprecatedMessage(command: string, url?: string, message?: string): void;
|
package/lib/ui/index.js
CHANGED
|
@@ -102,16 +102,17 @@ function uiBetaTag(message, log = true) {
|
|
|
102
102
|
logger_1.logger.log(result);
|
|
103
103
|
return;
|
|
104
104
|
}
|
|
105
|
-
|
|
106
|
-
return result;
|
|
107
|
-
}
|
|
105
|
+
return result;
|
|
108
106
|
}
|
|
109
|
-
function uiDeprecatedTag(message) {
|
|
107
|
+
function uiDeprecatedTag(message, log = true) {
|
|
110
108
|
const i18nKey = 'lib.ui';
|
|
111
109
|
const terminalUISupport = getTerminalUISupport();
|
|
112
110
|
const tag = (0, lang_1.i18n)(`${i18nKey}.deprecatedTag`);
|
|
113
111
|
const result = `${terminalUISupport.color ? chalk_1.default.yellow(tag) : tag} ${message}`;
|
|
114
|
-
|
|
112
|
+
if (log) {
|
|
113
|
+
logger_1.logger.log(result);
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
115
116
|
}
|
|
116
117
|
function uiCommandDisabledBanner(command, url, message) {
|
|
117
118
|
const i18nKey = 'lib.ui';
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.4.0-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": "3.
|
|
9
|
-
"@hubspot/project-parsing-lib": "0.1.
|
|
8
|
+
"@hubspot/local-dev-lib": "0.3.0-experimental.0",
|
|
9
|
+
"@hubspot/project-parsing-lib": "0.1.4",
|
|
10
10
|
"@hubspot/serverless-dev-runtime": "7.0.2",
|
|
11
11
|
"@hubspot/theme-preview-dev-server": "0.0.10",
|
|
12
12
|
"@hubspot/ui-extensions-dev-server": "0.8.52",
|
|
@@ -16,8 +16,23 @@ type AppConfig = {
|
|
|
16
16
|
conditionallyRequiredScopes: string[];
|
|
17
17
|
};
|
|
18
18
|
};
|
|
19
|
+
type CardConfig = {
|
|
20
|
+
name: string;
|
|
21
|
+
description: string;
|
|
22
|
+
previewImage: {
|
|
23
|
+
file: string;
|
|
24
|
+
altText: string;
|
|
25
|
+
};
|
|
26
|
+
entrypoint: string;
|
|
27
|
+
location: string;
|
|
28
|
+
objectTypes: string[];
|
|
29
|
+
};
|
|
19
30
|
export interface AppIRNode extends IntermediateRepresentationNodeLocalDev {
|
|
20
31
|
componentType: typeof IR_COMPONENT_TYPES.APPLICATION;
|
|
21
32
|
config: AppConfig;
|
|
22
33
|
}
|
|
34
|
+
export interface CardIRNode extends IntermediateRepresentationNodeLocalDev {
|
|
35
|
+
componentType: typeof IR_COMPONENT_TYPES.CARD;
|
|
36
|
+
config: CardConfig;
|
|
37
|
+
}
|
|
23
38
|
export {};
|
package/types/Prompts.d.ts
CHANGED
|
@@ -3,9 +3,9 @@ export type GenericPromptResponse = {
|
|
|
3
3
|
[key: string]: any;
|
|
4
4
|
};
|
|
5
5
|
type PromptType = 'confirm' | 'list' | 'checkbox' | 'input' | 'password' | 'number' | 'rawlist';
|
|
6
|
-
export type PromptChoices = Array<string | {
|
|
6
|
+
export type PromptChoices<T = any> = Array<string | {
|
|
7
7
|
name: string;
|
|
8
|
-
value?:
|
|
8
|
+
value?: T;
|
|
9
9
|
disabled?: string | boolean;
|
|
10
10
|
}>;
|
|
11
11
|
export type PromptWhen = boolean | (() => boolean);
|
package/types/Yargs.d.ts
CHANGED
|
@@ -27,3 +27,13 @@ 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
|
+
};
|