@hubspot/cli 7.3.0 → 7.4.1-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/migrateApp.d.ts +9 -1
- package/commands/project/migrateApp.js +43 -170
- package/lang/en.lyaml +32 -0
- 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/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 +2 -2
- package/types/Prompts.d.ts +2 -2
- package/types/Yargs.d.ts +10 -0
package/bin/cli.js
CHANGED
|
@@ -43,6 +43,7 @@ const cmsCommand = require('../commands/cms');
|
|
|
43
43
|
const feedbackCommand = require('../commands/feedback');
|
|
44
44
|
const doctorCommand = require('../commands/doctor');
|
|
45
45
|
const completionCommand = require('../commands/completion');
|
|
46
|
+
const appCommand = require('../commands/app');
|
|
46
47
|
const notifier = updateNotifier({
|
|
47
48
|
pkg: { ...pkg, name: '@hubspot/cli' },
|
|
48
49
|
distTag: 'latest',
|
|
@@ -294,6 +295,7 @@ const argv = yargs
|
|
|
294
295
|
.command(feedbackCommand)
|
|
295
296
|
.command(doctorCommand)
|
|
296
297
|
.command(completionCommand)
|
|
298
|
+
.command(appCommand)
|
|
297
299
|
.help()
|
|
298
300
|
.alias('h', 'help')
|
|
299
301
|
.recommendCommands()
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ArgumentsCamelCase, Argv, CommandModule } from 'yargs';
|
|
2
|
+
import { MigrateAppOptions } from '../../types/Yargs';
|
|
3
|
+
export declare const validMigrationTargets: string[];
|
|
4
|
+
export declare function handler(options: ArgumentsCamelCase<MigrateAppOptions>): Promise<never>;
|
|
5
|
+
export declare function builder(yargs: Argv): Argv<MigrateAppOptions>;
|
|
6
|
+
declare const migrateCommand: CommandModule<unknown, MigrateAppOptions>;
|
|
7
|
+
export default migrateCommand;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validMigrationTargets = void 0;
|
|
4
|
+
exports.handler = handler;
|
|
5
|
+
exports.builder = builder;
|
|
6
|
+
const commonOpts_1 = require("../../lib/commonOpts");
|
|
7
|
+
const usageTracking_1 = require("../../lib/usageTracking");
|
|
8
|
+
const lang_1 = require("../../lib/lang");
|
|
9
|
+
const errorHandlers_1 = require("../../lib/errorHandlers");
|
|
10
|
+
const exitCodes_1 = require("../../lib/enums/exitCodes");
|
|
11
|
+
const config_1 = require("@hubspot/local-dev-lib/config");
|
|
12
|
+
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
|
+
const ui_1 = require("../../lib/ui");
|
|
16
|
+
const { v2023_2, v2025_2, unstable } = projects_1.PLATFORM_VERSIONS;
|
|
17
|
+
exports.validMigrationTargets = [v2023_2, v2025_2, unstable];
|
|
18
|
+
const command = 'migrate';
|
|
19
|
+
const describe = undefined; // uiBetaTag(i18n(`commands.project.subcommands.migrateApp.header.text.describe`), false);
|
|
20
|
+
async function handler(options) {
|
|
21
|
+
const { derivedAccountId, platformVersion } = options;
|
|
22
|
+
await (0, usageTracking_1.trackCommandUsage)('migrate-app', {}, derivedAccountId);
|
|
23
|
+
const accountConfig = (0, config_1.getAccountConfig)(derivedAccountId);
|
|
24
|
+
if (!accountConfig) {
|
|
25
|
+
logger_1.logger.error((0, lang_1.i18n)(`commands.project.subcommands.migrateApp.errors.noAccountConfig`));
|
|
26
|
+
return process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
27
|
+
}
|
|
28
|
+
logger_1.logger.log('');
|
|
29
|
+
logger_1.logger.log((0, ui_1.uiBetaTag)((0, lang_1.i18n)(`commands.project.subcommands.migrateApp.header.text`), false));
|
|
30
|
+
logger_1.logger.log((0, ui_1.uiLink)((0, lang_1.i18n)(`commands.project.subcommands.migrateApp.header.link`), 'https://developers.hubspot.com/docs/platform/migrate-a-public-app-to-projects'));
|
|
31
|
+
logger_1.logger.log('');
|
|
32
|
+
try {
|
|
33
|
+
if (platformVersion === v2025_2 || platformVersion === unstable) {
|
|
34
|
+
await (0, migrate_1.migrateApp2025_2)(derivedAccountId, options);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
await (0, migrate_1.migrateApp2023_2)(derivedAccountId, options, accountConfig);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
if (error &&
|
|
42
|
+
typeof error === 'object' &&
|
|
43
|
+
'errors' in error &&
|
|
44
|
+
Array.isArray(error.errors)) {
|
|
45
|
+
error.errors.forEach(err => (0, errorHandlers_1.logError)(err));
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
(0, errorHandlers_1.logError)(error, new errorHandlers_1.ApiErrorContext({ accountId: derivedAccountId }));
|
|
49
|
+
}
|
|
50
|
+
await (0, usageTracking_1.trackCommandMetadataUsage)('migrate-app', { successful: false }, derivedAccountId);
|
|
51
|
+
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
52
|
+
}
|
|
53
|
+
await (0, usageTracking_1.trackCommandMetadataUsage)('migrate-app', { successful: true }, derivedAccountId);
|
|
54
|
+
return process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
55
|
+
}
|
|
56
|
+
function builder(yargs) {
|
|
57
|
+
(0, commonOpts_1.addConfigOptions)(yargs);
|
|
58
|
+
(0, commonOpts_1.addAccountOptions)(yargs);
|
|
59
|
+
(0, commonOpts_1.addUseEnvironmentOptions)(yargs);
|
|
60
|
+
yargs.options({
|
|
61
|
+
name: {
|
|
62
|
+
describe: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.options.name.describe`),
|
|
63
|
+
type: 'string',
|
|
64
|
+
},
|
|
65
|
+
dest: {
|
|
66
|
+
describe: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.options.dest.describe`),
|
|
67
|
+
type: 'string',
|
|
68
|
+
},
|
|
69
|
+
'app-id': {
|
|
70
|
+
describe: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.options.appId.describe`),
|
|
71
|
+
type: 'number',
|
|
72
|
+
},
|
|
73
|
+
'platform-version': {
|
|
74
|
+
type: 'string',
|
|
75
|
+
choices: exports.validMigrationTargets,
|
|
76
|
+
hidden: true,
|
|
77
|
+
default: '2023.2',
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
yargs.example([
|
|
81
|
+
[
|
|
82
|
+
`$0 app migrate`,
|
|
83
|
+
(0, lang_1.i18n)(`commands.project.subcommands.migrateApp.examples.default`),
|
|
84
|
+
],
|
|
85
|
+
]);
|
|
86
|
+
return yargs;
|
|
87
|
+
}
|
|
88
|
+
const migrateCommand = {
|
|
89
|
+
command,
|
|
90
|
+
describe,
|
|
91
|
+
handler,
|
|
92
|
+
builder,
|
|
93
|
+
};
|
|
94
|
+
exports.default = migrateCommand;
|
package/commands/app.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
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.describe = exports.command = void 0;
|
|
7
|
+
exports.builder = builder;
|
|
8
|
+
const migrate_1 = __importDefault(require("./app/migrate"));
|
|
9
|
+
const commonOpts_1 = require("../lib/commonOpts");
|
|
10
|
+
exports.command = ['app', 'apps'];
|
|
11
|
+
// Keep the command hidden for now
|
|
12
|
+
exports.describe = undefined;
|
|
13
|
+
function builder(yargs) {
|
|
14
|
+
(0, commonOpts_1.addGlobalOptions)(yargs);
|
|
15
|
+
return yargs.command(migrate_1.default).demandCommand(1, '');
|
|
16
|
+
}
|
|
17
|
+
const appCommand = {
|
|
18
|
+
command: exports.command,
|
|
19
|
+
describe: exports.describe,
|
|
20
|
+
builder,
|
|
21
|
+
handler: () => { },
|
|
22
|
+
};
|
|
23
|
+
exports.default = appCommand;
|
|
@@ -1 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import { ArgumentsCamelCase, Argv, CommandModule } from 'yargs';
|
|
2
|
+
import { CloneAppArgs } from '../../types/Yargs';
|
|
3
|
+
export declare const command = "clone-app";
|
|
4
|
+
export declare const describe: string | undefined;
|
|
5
|
+
export declare const deprecated = true;
|
|
6
|
+
export declare const handler: (options: ArgumentsCamelCase<CloneAppArgs>) => Promise<never>;
|
|
7
|
+
export declare const builder: (yargs: Argv) => Argv<CloneAppArgs>;
|
|
8
|
+
declare const cloneAppCommand: CommandModule<unknown, CloneAppArgs>;
|
|
9
|
+
export default cloneAppCommand;
|
|
@@ -1,43 +1,46 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
6
|
+
exports.builder = exports.handler = exports.deprecated = exports.describe = exports.command = void 0;
|
|
7
|
+
const ui_1 = require("../../lib/ui");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const commonOpts_1 = require("../../lib/commonOpts");
|
|
11
|
+
const usageTracking_1 = require("../../lib/usageTracking");
|
|
12
|
+
const lang_1 = require("../../lib/lang");
|
|
13
|
+
const selectPublicAppPrompt_1 = require("../../lib/prompts/selectPublicAppPrompt");
|
|
14
|
+
const createProjectPrompt_1 = require("../../lib/prompts/createProjectPrompt");
|
|
15
|
+
const polling_1 = require("../../lib/polling");
|
|
16
|
+
const ui_2 = require("../../lib/ui");
|
|
17
|
+
const errorHandlers_1 = require("../../lib/errorHandlers");
|
|
18
|
+
const exitCodes_1 = require("../../lib/enums/exitCodes");
|
|
19
|
+
const accountTypes_1 = require("../../lib/accountTypes");
|
|
20
|
+
const projects_1 = require("../../lib/projects");
|
|
21
|
+
const constants_1 = require("../../lib/constants");
|
|
22
|
+
const projects_2 = require("@hubspot/local-dev-lib/api/projects");
|
|
23
|
+
const path_2 = require("@hubspot/local-dev-lib/path");
|
|
24
|
+
const logger_1 = require("@hubspot/local-dev-lib/logger");
|
|
25
|
+
const archive_1 = require("@hubspot/local-dev-lib/archive");
|
|
26
|
+
const config_1 = require("@hubspot/local-dev-lib/config");
|
|
27
|
+
const SpinniesManager_1 = __importDefault(require("../../lib/ui/SpinniesManager"));
|
|
28
|
+
const migrate_1 = require("../../lib/app/migrate");
|
|
24
29
|
const i18nKey = 'commands.project.subcommands.cloneApp';
|
|
25
30
|
exports.command = 'clone-app';
|
|
26
|
-
exports.describe =
|
|
27
|
-
exports.
|
|
31
|
+
exports.describe = (0, ui_1.uiDeprecatedTag)((0, lang_1.i18n)(`${i18nKey}.describe`), false);
|
|
32
|
+
exports.deprecated = true;
|
|
33
|
+
const handler = async (options) => {
|
|
28
34
|
const { derivedAccountId } = options;
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
if (!
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}));
|
|
39
|
-
uiLine();
|
|
40
|
-
process.exit(EXIT_CODES.SUCCESS);
|
|
35
|
+
await (0, usageTracking_1.trackCommandUsage)('clone-app', {}, derivedAccountId);
|
|
36
|
+
const accountConfig = (0, config_1.getAccountConfig)(derivedAccountId);
|
|
37
|
+
const accountName = (0, ui_2.uiAccountDescription)(derivedAccountId);
|
|
38
|
+
if (!accountConfig) {
|
|
39
|
+
throw new Error((0, lang_1.i18n)(`commands.projects.subcommands.cloneApp.errors.noAccountConfig`));
|
|
40
|
+
}
|
|
41
|
+
if (!(0, accountTypes_1.isAppDeveloperAccount)(accountConfig)) {
|
|
42
|
+
(0, migrate_1.logInvalidAccountError)(i18nKey);
|
|
43
|
+
process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
41
44
|
}
|
|
42
45
|
let appId;
|
|
43
46
|
let projectName;
|
|
@@ -45,96 +48,108 @@ exports.handler = async (options) => {
|
|
|
45
48
|
try {
|
|
46
49
|
appId = options.appId;
|
|
47
50
|
if (!appId) {
|
|
48
|
-
const appIdResponse = await selectPublicAppPrompt({
|
|
51
|
+
const appIdResponse = await (0, selectPublicAppPrompt_1.selectPublicAppPrompt)({
|
|
49
52
|
accountId: derivedAccountId,
|
|
50
53
|
accountName,
|
|
51
|
-
options,
|
|
52
54
|
isMigratingApp: false,
|
|
53
55
|
});
|
|
54
56
|
appId = appIdResponse.appId;
|
|
55
57
|
}
|
|
56
|
-
const createProjectPromptResponse = await createProjectPrompt(options);
|
|
58
|
+
const createProjectPromptResponse = await (0, createProjectPrompt_1.createProjectPrompt)(options);
|
|
57
59
|
projectName = createProjectPromptResponse.name;
|
|
58
60
|
projectDest = createProjectPromptResponse.dest;
|
|
59
61
|
}
|
|
60
62
|
catch (error) {
|
|
61
|
-
logError(error, new ApiErrorContext({ accountId: derivedAccountId }));
|
|
62
|
-
process.exit(EXIT_CODES.ERROR);
|
|
63
|
+
(0, errorHandlers_1.logError)(error, new errorHandlers_1.ApiErrorContext({ accountId: derivedAccountId }));
|
|
64
|
+
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
63
65
|
}
|
|
64
|
-
await trackCommandMetadataUsage('clone-app', {
|
|
66
|
+
await (0, usageTracking_1.trackCommandMetadataUsage)('clone-app', { step: 'STARTED' }, derivedAccountId);
|
|
65
67
|
try {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
text: i18n(`${i18nKey}.cloneStatus.inProgress`),
|
|
68
|
+
SpinniesManager_1.default.init();
|
|
69
|
+
SpinniesManager_1.default.add('cloneApp', {
|
|
70
|
+
text: (0, lang_1.i18n)(`${i18nKey}.cloneStatus.inProgress`),
|
|
69
71
|
});
|
|
70
|
-
const { data: { exportId }, } = await cloneApp(derivedAccountId, appId);
|
|
71
|
-
const { status } = await poll(() => checkCloneStatus(derivedAccountId, exportId));
|
|
72
|
+
const { data: { exportId }, } = await (0, projects_2.cloneApp)(derivedAccountId, appId);
|
|
73
|
+
const { status } = await (0, polling_1.poll)(() => (0, projects_2.checkCloneStatus)(derivedAccountId, exportId));
|
|
72
74
|
if (status === 'SUCCESS') {
|
|
73
75
|
// Ensure correct project folder structure exists
|
|
74
|
-
const baseDestPath =
|
|
75
|
-
const absoluteDestPath =
|
|
76
|
-
|
|
76
|
+
const baseDestPath = path_1.default.resolve((0, path_2.getCwd)(), projectDest);
|
|
77
|
+
const absoluteDestPath = path_1.default.resolve(baseDestPath, 'src', 'app');
|
|
78
|
+
fs_1.default.mkdirSync(absoluteDestPath, { recursive: true });
|
|
77
79
|
// Extract zipped app files and place them in correct directory
|
|
78
|
-
const { data: zippedApp } = await downloadClonedProject(derivedAccountId, exportId);
|
|
79
|
-
await extractZipArchive(zippedApp, sanitizeFileName(projectName), absoluteDestPath, {
|
|
80
|
+
const { data: zippedApp } = await (0, projects_2.downloadClonedProject)(derivedAccountId, exportId);
|
|
81
|
+
await (0, archive_1.extractZipArchive)(zippedApp, (0, path_2.sanitizeFileName)(projectName), absoluteDestPath, {
|
|
80
82
|
includesRootDir: true,
|
|
81
83
|
hideLogs: true,
|
|
82
84
|
});
|
|
83
85
|
// Create hsproject.json file
|
|
84
|
-
const configPath =
|
|
86
|
+
const configPath = path_1.default.join(baseDestPath, constants_1.PROJECT_CONFIG_FILE);
|
|
85
87
|
const configContent = {
|
|
86
88
|
name: projectName,
|
|
87
89
|
srcDir: 'src',
|
|
88
90
|
platformVersion: '2023.2',
|
|
89
91
|
};
|
|
90
|
-
const success = writeProjectConfig(configPath, configContent);
|
|
91
|
-
|
|
92
|
-
text: i18n(`${i18nKey}.cloneStatus.done`),
|
|
92
|
+
const success = (0, projects_1.writeProjectConfig)(configPath, configContent);
|
|
93
|
+
SpinniesManager_1.default.succeed('cloneApp', {
|
|
94
|
+
text: (0, lang_1.i18n)(`${i18nKey}.cloneStatus.done`),
|
|
93
95
|
succeedColor: 'white',
|
|
94
96
|
});
|
|
95
97
|
if (!success) {
|
|
96
|
-
logger.error(i18n(`${i18nKey}.errors.couldNotWriteConfigPath`), configPath);
|
|
98
|
+
logger_1.logger.error((0, lang_1.i18n)(`${i18nKey}.errors.couldNotWriteConfigPath`), configPath);
|
|
97
99
|
}
|
|
98
|
-
logger.log('');
|
|
99
|
-
uiLine();
|
|
100
|
-
logger.success(i18n(`${i18nKey}.cloneStatus.success`, { dest }));
|
|
101
|
-
logger.log('');
|
|
102
|
-
process.exit(EXIT_CODES.SUCCESS);
|
|
100
|
+
logger_1.logger.log('');
|
|
101
|
+
(0, ui_2.uiLine)();
|
|
102
|
+
logger_1.logger.success((0, lang_1.i18n)(`${i18nKey}.cloneStatus.success`, { dest: projectDest }));
|
|
103
|
+
logger_1.logger.log('');
|
|
104
|
+
process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
103
105
|
}
|
|
104
106
|
}
|
|
105
107
|
catch (error) {
|
|
106
|
-
await trackCommandMetadataUsage('clone-app', {
|
|
107
|
-
|
|
108
|
-
text: i18n(`${i18nKey}.cloneStatus.failure`),
|
|
108
|
+
await (0, usageTracking_1.trackCommandMetadataUsage)('clone-app', { successful: false }, derivedAccountId);
|
|
109
|
+
SpinniesManager_1.default.fail('cloneApp', {
|
|
110
|
+
text: (0, lang_1.i18n)(`${i18nKey}.cloneStatus.failure`),
|
|
109
111
|
failColor: 'white',
|
|
110
112
|
});
|
|
111
113
|
// Migrations endpoints return a response object with an errors property. The errors property contains an array of errors.
|
|
112
|
-
if (error
|
|
113
|
-
error
|
|
114
|
+
if (error &&
|
|
115
|
+
typeof error === 'object' &&
|
|
116
|
+
'errors' in error &&
|
|
117
|
+
Array.isArray(error.errors)) {
|
|
118
|
+
error.errors.forEach(e => (0, errorHandlers_1.logError)(e, new errorHandlers_1.ApiErrorContext({ accountId: derivedAccountId })));
|
|
114
119
|
}
|
|
115
120
|
else {
|
|
116
|
-
logError(error, new ApiErrorContext({ accountId: derivedAccountId }));
|
|
121
|
+
(0, errorHandlers_1.logError)(error, new errorHandlers_1.ApiErrorContext({ accountId: derivedAccountId }));
|
|
117
122
|
}
|
|
118
123
|
}
|
|
119
|
-
await trackCommandMetadataUsage('clone-app', {
|
|
120
|
-
process.exit(EXIT_CODES.SUCCESS);
|
|
124
|
+
await (0, usageTracking_1.trackCommandMetadataUsage)('clone-app', { successful: true }, derivedAccountId);
|
|
125
|
+
process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
121
126
|
};
|
|
122
|
-
exports.
|
|
127
|
+
exports.handler = handler;
|
|
128
|
+
const builder = (yargs) => {
|
|
123
129
|
yargs.options({
|
|
124
130
|
dest: {
|
|
125
|
-
describe: i18n(`${i18nKey}.options.dest.describe`),
|
|
131
|
+
describe: (0, lang_1.i18n)(`${i18nKey}.options.dest.describe`),
|
|
126
132
|
type: 'string',
|
|
127
133
|
},
|
|
128
134
|
'app-id': {
|
|
129
|
-
describe: i18n(`${i18nKey}.options.appId.describe`),
|
|
135
|
+
describe: (0, lang_1.i18n)(`${i18nKey}.options.appId.describe`),
|
|
130
136
|
type: 'number',
|
|
131
137
|
},
|
|
132
138
|
});
|
|
133
139
|
yargs.example([
|
|
134
|
-
['$0 project clone-app', i18n(`${i18nKey}.examples.default`)],
|
|
140
|
+
['$0 project clone-app', (0, lang_1.i18n)(`${i18nKey}.examples.default`)],
|
|
135
141
|
]);
|
|
136
|
-
addConfigOptions(yargs);
|
|
137
|
-
addAccountOptions(yargs);
|
|
138
|
-
addUseEnvironmentOptions(yargs);
|
|
142
|
+
(0, commonOpts_1.addConfigOptions)(yargs);
|
|
143
|
+
(0, commonOpts_1.addAccountOptions)(yargs);
|
|
144
|
+
(0, commonOpts_1.addUseEnvironmentOptions)(yargs);
|
|
139
145
|
return yargs;
|
|
140
146
|
};
|
|
147
|
+
exports.builder = builder;
|
|
148
|
+
const cloneAppCommand = {
|
|
149
|
+
command: exports.command,
|
|
150
|
+
describe: exports.describe,
|
|
151
|
+
handler: exports.handler,
|
|
152
|
+
builder: exports.builder,
|
|
153
|
+
deprecated: exports.deprecated,
|
|
154
|
+
};
|
|
155
|
+
exports.default = cloneAppCommand;
|
|
@@ -1 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import { ArgumentsCamelCase, Argv, CommandModule } from 'yargs';
|
|
2
|
+
import { MigrateAppOptions } from '../../types/Yargs';
|
|
3
|
+
export declare const command = "migrate-app";
|
|
4
|
+
export declare const describe: string | undefined;
|
|
5
|
+
export declare const deprecated = true;
|
|
6
|
+
export declare function handler(yargs: ArgumentsCamelCase<MigrateAppOptions>): Promise<void>;
|
|
7
|
+
export declare function builder(yargs: Argv): Argv<MigrateAppOptions>;
|
|
8
|
+
declare const migrateAppCommand: CommandModule<unknown, MigrateAppOptions>;
|
|
9
|
+
export default migrateAppCommand;
|
|
@@ -1,188 +1,61 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const { uiBetaTag, uiLine, uiLink, uiCommandReference, uiAccountDescription, } = require('../../lib/ui');
|
|
12
|
-
const SpinniesManager = require('../../lib/ui/SpinniesManager');
|
|
13
|
-
const { logError, ApiErrorContext } = require('../../lib/errorHandlers/index');
|
|
14
|
-
const { EXIT_CODES } = require('../../lib/enums/exitCodes');
|
|
15
|
-
const { promptUser } = require('../../lib/prompts/promptUtils');
|
|
16
|
-
const { isAppDeveloperAccount } = require('../../lib/accountTypes');
|
|
17
|
-
const { ensureProjectExists } = require('../../lib/projects');
|
|
18
|
-
const { handleKeypress } = require('../../lib/process');
|
|
19
|
-
const { migrateApp, checkMigrationStatus, } = require('@hubspot/local-dev-lib/api/projects');
|
|
20
|
-
const { getCwd, sanitizeFileName } = require('@hubspot/local-dev-lib/path');
|
|
21
|
-
const { logger } = require('@hubspot/local-dev-lib/logger');
|
|
22
|
-
const { getAccountConfig } = require('@hubspot/local-dev-lib/config');
|
|
23
|
-
const { downloadProject } = require('@hubspot/local-dev-lib/api/projects');
|
|
24
|
-
const { extractZipArchive } = require('@hubspot/local-dev-lib/archive');
|
|
25
|
-
const { getHubSpotWebsiteOrigin } = require('@hubspot/local-dev-lib/urls');
|
|
26
|
-
const { fetchPublicAppMetadata, } = require('@hubspot/local-dev-lib/api/appsDev');
|
|
27
|
-
const i18nKey = 'commands.project.subcommands.migrateApp';
|
|
3
|
+
exports.deprecated = exports.describe = exports.command = void 0;
|
|
4
|
+
exports.handler = handler;
|
|
5
|
+
exports.builder = builder;
|
|
6
|
+
const lang_1 = require("../../lib/lang");
|
|
7
|
+
const ui_1 = require("../../lib/ui");
|
|
8
|
+
const migrate_1 = require("../app/migrate");
|
|
9
|
+
const logger_1 = require("@hubspot/local-dev-lib/logger");
|
|
10
|
+
const commonOpts_1 = require("../../lib/commonOpts");
|
|
28
11
|
exports.command = 'migrate-app';
|
|
29
|
-
|
|
30
|
-
exports.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
useCommand: uiCommandReference('hs accounts use'),
|
|
44
|
-
authCommand: uiCommandReference('hs auth'),
|
|
45
|
-
}));
|
|
46
|
-
uiLine();
|
|
47
|
-
process.exit(EXIT_CODES.SUCCESS);
|
|
48
|
-
}
|
|
49
|
-
const { appId } = 'appId' in options
|
|
50
|
-
? options
|
|
51
|
-
: await selectPublicAppPrompt({
|
|
52
|
-
accountId: derivedAccountId,
|
|
53
|
-
accountName,
|
|
54
|
-
isMigratingApp: true,
|
|
55
|
-
});
|
|
56
|
-
try {
|
|
57
|
-
const { data: selectedApp } = await fetchPublicAppMetadata(appId, derivedAccountId);
|
|
58
|
-
// preventProjectMigrations returns true if we have not added app to allowlist config.
|
|
59
|
-
// listingInfo will only exist for marketplace apps
|
|
60
|
-
const preventProjectMigrations = selectedApp.preventProjectMigrations;
|
|
61
|
-
const listingInfo = selectedApp.listingInfo;
|
|
62
|
-
if (preventProjectMigrations && listingInfo) {
|
|
63
|
-
logger.error(i18n(`${i18nKey}.errors.invalidApp`, { appId }));
|
|
64
|
-
process.exit(EXIT_CODES.ERROR);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
catch (error) {
|
|
68
|
-
logError(error, new ApiErrorContext({ accountId: derivedAccountId }));
|
|
69
|
-
process.exit(EXIT_CODES.ERROR);
|
|
70
|
-
}
|
|
71
|
-
let projectName;
|
|
72
|
-
let projectDest;
|
|
73
|
-
try {
|
|
74
|
-
const createProjectPromptResponse = await createProjectPrompt(options);
|
|
75
|
-
projectName = createProjectPromptResponse.name;
|
|
76
|
-
projectDest = createProjectPromptResponse.dest;
|
|
77
|
-
const { projectExists } = await ensureProjectExists(derivedAccountId, projectName, {
|
|
78
|
-
allowCreate: false,
|
|
79
|
-
noLogs: true,
|
|
80
|
-
});
|
|
81
|
-
if (projectExists) {
|
|
82
|
-
logger.error(i18n(`${i18nKey}.errors.projectAlreadyExists`, {
|
|
83
|
-
projectName,
|
|
84
|
-
}));
|
|
85
|
-
process.exit(EXIT_CODES.ERROR);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
logError(error, new ApiErrorContext({ accountId: derivedAccountId }));
|
|
90
|
-
process.exit(EXIT_CODES.ERROR);
|
|
91
|
-
}
|
|
92
|
-
await trackCommandMetadataUsage('migrate-app', { status: 'STARTED' }, derivedAccountId);
|
|
93
|
-
logger.log('');
|
|
94
|
-
uiLine();
|
|
95
|
-
logger.warn(i18n(`${i18nKey}.warning.title`));
|
|
96
|
-
logger.log('');
|
|
97
|
-
logger.log(i18n(`${i18nKey}.warning.projectConversion`));
|
|
98
|
-
logger.log(i18n(`${i18nKey}.warning.appConfig`));
|
|
99
|
-
logger.log('');
|
|
100
|
-
logger.log(i18n(`${i18nKey}.warning.buildAndDeploy`));
|
|
101
|
-
logger.log('');
|
|
102
|
-
logger.log(i18n(`${i18nKey}.warning.existingApps`));
|
|
103
|
-
logger.log('');
|
|
104
|
-
logger.log(i18n(`${i18nKey}.warning.copyApp`));
|
|
105
|
-
uiLine();
|
|
106
|
-
const { shouldCreateApp } = await promptUser({
|
|
107
|
-
name: 'shouldCreateApp',
|
|
108
|
-
type: 'confirm',
|
|
109
|
-
message: i18n(`${i18nKey}.createAppPrompt`),
|
|
110
|
-
});
|
|
111
|
-
process.stdin.resume();
|
|
112
|
-
if (!shouldCreateApp) {
|
|
113
|
-
process.exit(EXIT_CODES.SUCCESS);
|
|
114
|
-
}
|
|
115
|
-
try {
|
|
116
|
-
SpinniesManager.init();
|
|
117
|
-
SpinniesManager.add('migrateApp', {
|
|
118
|
-
text: i18n(`${i18nKey}.migrationStatus.inProgress`),
|
|
119
|
-
});
|
|
120
|
-
handleKeypress(async (key) => {
|
|
121
|
-
if ((key.ctrl && key.name === 'c') || key.name === 'q') {
|
|
122
|
-
SpinniesManager.remove('migrateApp');
|
|
123
|
-
logger.log(i18n(`${i18nKey}.migrationInterrupted`));
|
|
124
|
-
process.exit(EXIT_CODES.SUCCESS);
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
const { data: migrateResponse } = await migrateApp(derivedAccountId, appId, projectName);
|
|
128
|
-
const { id } = migrateResponse;
|
|
129
|
-
const pollResponse = await poll(() => checkMigrationStatus(derivedAccountId, id));
|
|
130
|
-
const { status, project } = pollResponse;
|
|
131
|
-
if (status === 'SUCCESS') {
|
|
132
|
-
const absoluteDestPath = path.resolve(getCwd(), projectDest);
|
|
133
|
-
const { env } = accountConfig;
|
|
134
|
-
const baseUrl = getHubSpotWebsiteOrigin(env);
|
|
135
|
-
const { data: zippedProject } = await downloadProject(derivedAccountId, projectName, 1);
|
|
136
|
-
await extractZipArchive(zippedProject, sanitizeFileName(projectName), path.resolve(absoluteDestPath), { includesRootDir: true, hideLogs: true });
|
|
137
|
-
SpinniesManager.succeed('migrateApp', {
|
|
138
|
-
text: i18n(`${i18nKey}.migrationStatus.done`),
|
|
139
|
-
succeedColor: 'white',
|
|
140
|
-
});
|
|
141
|
-
logger.log('');
|
|
142
|
-
uiLine();
|
|
143
|
-
logger.success(i18n(`${i18nKey}.migrationStatus.success`));
|
|
144
|
-
logger.log('');
|
|
145
|
-
logger.log(uiLink(i18n(`${i18nKey}.projectDetailsLink`), `${baseUrl}/developer-projects/${derivedAccountId}/project/${encodeURIComponent(project.name)}`));
|
|
146
|
-
process.exit(EXIT_CODES.SUCCESS);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
catch (error) {
|
|
150
|
-
await trackCommandMetadataUsage('migrate-app', { status: 'FAILURE' }, derivedAccountId);
|
|
151
|
-
SpinniesManager.fail('migrateApp', {
|
|
152
|
-
text: i18n(`${i18nKey}.migrationStatus.failure`),
|
|
153
|
-
failColor: 'white',
|
|
154
|
-
});
|
|
155
|
-
if (error.errors) {
|
|
156
|
-
error.errors.forEach(logError);
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
logError(error, new ApiErrorContext({ accountId: derivedAccountId }));
|
|
160
|
-
}
|
|
161
|
-
process.exit(EXIT_CODES.ERROR);
|
|
162
|
-
}
|
|
163
|
-
await trackCommandMetadataUsage('migrate-app', { status: 'SUCCESS' }, derivedAccountId);
|
|
164
|
-
process.exit(EXIT_CODES.SUCCESS);
|
|
165
|
-
};
|
|
166
|
-
exports.builder = yargs => {
|
|
12
|
+
// TODO: Leave this as deprecated and remove in the next major release
|
|
13
|
+
exports.describe = (0, ui_1.uiDeprecatedTag)((0, lang_1.i18n)(`commands.project.subcommands.migrateApp.describe`), false);
|
|
14
|
+
exports.deprecated = true;
|
|
15
|
+
async function handler(yargs) {
|
|
16
|
+
logger_1.logger.warn((0, lang_1.i18n)(`commands.project.subcommands.migrateApp.deprecationWarning`, {
|
|
17
|
+
oldCommand: (0, ui_1.uiCommandReference)('hs project migrate-app'),
|
|
18
|
+
newCommand: (0, ui_1.uiCommandReference)('hs app migrate'),
|
|
19
|
+
}));
|
|
20
|
+
await (0, migrate_1.handler)(yargs);
|
|
21
|
+
}
|
|
22
|
+
function builder(yargs) {
|
|
23
|
+
(0, commonOpts_1.addConfigOptions)(yargs);
|
|
24
|
+
(0, commonOpts_1.addAccountOptions)(yargs);
|
|
25
|
+
(0, commonOpts_1.addUseEnvironmentOptions)(yargs);
|
|
167
26
|
yargs.options({
|
|
168
27
|
name: {
|
|
169
|
-
describe: i18n(
|
|
28
|
+
describe: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.options.name.describe`),
|
|
170
29
|
type: 'string',
|
|
171
30
|
},
|
|
172
31
|
dest: {
|
|
173
|
-
describe: i18n(
|
|
32
|
+
describe: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.options.dest.describe`),
|
|
174
33
|
type: 'string',
|
|
175
34
|
},
|
|
176
35
|
'app-id': {
|
|
177
|
-
describe: i18n(
|
|
36
|
+
describe: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.options.appId.describe`),
|
|
178
37
|
type: 'number',
|
|
179
38
|
},
|
|
39
|
+
'platform-version': {
|
|
40
|
+
type: 'string',
|
|
41
|
+
choices: migrate_1.validMigrationTargets,
|
|
42
|
+
hidden: true,
|
|
43
|
+
default: '2023.2',
|
|
44
|
+
},
|
|
180
45
|
});
|
|
181
46
|
yargs.example([
|
|
182
|
-
[
|
|
47
|
+
[
|
|
48
|
+
`$0 project migrate-app`,
|
|
49
|
+
(0, lang_1.i18n)(`commands.project.subcommands.migrateApp.examples.default`),
|
|
50
|
+
],
|
|
183
51
|
]);
|
|
184
|
-
addConfigOptions(yargs);
|
|
185
|
-
addAccountOptions(yargs);
|
|
186
|
-
addUseEnvironmentOptions(yargs);
|
|
187
52
|
return yargs;
|
|
53
|
+
}
|
|
54
|
+
const migrateAppCommand = {
|
|
55
|
+
command: exports.command,
|
|
56
|
+
describe: exports.describe,
|
|
57
|
+
deprecated: exports.deprecated,
|
|
58
|
+
handler,
|
|
59
|
+
builder,
|
|
188
60
|
};
|
|
61
|
+
exports.default = migrateAppCommand;
|
package/lang/en.lyaml
CHANGED
|
@@ -570,6 +570,7 @@ en:
|
|
|
570
570
|
header:
|
|
571
571
|
text: "Migrate an app to the projects framework"
|
|
572
572
|
link: "Learn more about migrating apps to the projects framework"
|
|
573
|
+
deprecationWarning: "The {{ oldCommand }} command is deprecated and will be removed. Use {{ newCommand }} going forward."
|
|
573
574
|
migrationStatus:
|
|
574
575
|
inProgress: "Converting app configuration to {{#bold}}public-app.json{{/bold}} component definition ..."
|
|
575
576
|
success: "{{#bold}}Your app was converted and build #1 is deployed{{/bold}}"
|
|
@@ -585,11 +586,41 @@ en:
|
|
|
585
586
|
migrationInterrupted: "\nThe command is terminated, but app migration is still in progress. Please check your account to ensure that the project and associated app have been created successfully."
|
|
586
587
|
createAppPrompt: "Proceed with migrating this app to a project component (this process can't be aborted)?"
|
|
587
588
|
projectDetailsLink: "View project details in your developer account"
|
|
589
|
+
componentsToBeMigrated: "The following component types will be migrated: {{ components }}"
|
|
590
|
+
componentsThatWillNotBeMigrated: "[NOTE] These component types are not yet supported for migration but will be available later: {{ components }}"
|
|
588
591
|
errors:
|
|
592
|
+
noApps: "No apps found in account {{ accountId }}"
|
|
593
|
+
noAppsEligible: "No apps in account {{ accountId }} are currently migratable"
|
|
594
|
+
noAccountConfig: "There is no account associated with {{ accountId }} in the config file. Please choose another account and try again, or authenticate {{ accountId }} using {{ authCommand }}."
|
|
589
595
|
invalidAccountTypeTitle: "{{#bold}}Developer account not targeted{{/bold}}"
|
|
590
596
|
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."
|
|
591
597
|
projectAlreadyExists: "A project with name {{ projectName }} already exists. Please choose another name."
|
|
592
598
|
invalidApp: "Could not migrate appId {{ appId }}. This app cannot be migrated at this time. Please choose another public app."
|
|
599
|
+
appWithAppIdNotFound: "Could not find an app with the id {{ appId }} "
|
|
600
|
+
prompt:
|
|
601
|
+
chooseApp: 'Which app would you like to migrate?'
|
|
602
|
+
inputName: '[--name] What would you like to name the project?'
|
|
603
|
+
inputDest: '[--dest] Where would you like to save the project?'
|
|
604
|
+
uidForComponent: 'What UID would you like to use for {{ componentName }}?'
|
|
605
|
+
proceed: 'Would you like to proceed?'
|
|
606
|
+
spinners:
|
|
607
|
+
beginningMigration: "Beginning migration"
|
|
608
|
+
migrationStarted: "Migration started"
|
|
609
|
+
unableToStartMigration: "Unable to begin migration"
|
|
610
|
+
finishingMigration: "Wrapping up migration"
|
|
611
|
+
migrationComplete: "Migration completed"
|
|
612
|
+
migrationFailed: "Migration failed"
|
|
613
|
+
downloadingProjectContents: "Downloading migrated project files"
|
|
614
|
+
downloadingProjectContentsComplete: "Migrated project files downloaded"
|
|
615
|
+
downloadingProjectContentsFailed: "Unable to download migrated project files"
|
|
616
|
+
copyingProjectFiles: "Copying migrated project files"
|
|
617
|
+
copyingProjectFilesComplete: "Migrated project files copied"
|
|
618
|
+
copyingProjectFilesFailed: "Unable to copy migrated project files"
|
|
619
|
+
unmigratableReasons:
|
|
620
|
+
upToDate: 'App is already up to date'
|
|
621
|
+
isPrivateApp: 'Private apps are not currently migratable'
|
|
622
|
+
listedInMarketplace: 'Listed apps are not currently migratable'
|
|
623
|
+
generic: "Unable to migrate app: {{ reasonCode }}"
|
|
593
624
|
cloneApp:
|
|
594
625
|
describe: "Clone a public app using the projects framework."
|
|
595
626
|
examples:
|
|
@@ -608,6 +639,7 @@ en:
|
|
|
608
639
|
invalidAccountTypeTitle: "{{#bold}}Developer account not targeted{{/bold}}"
|
|
609
640
|
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."
|
|
610
641
|
couldNotWriteConfigPath: "Failed to write project config at {{ configPath }}"
|
|
642
|
+
noAccountConfig: "There is no account associated with {{ accountId }} in the config file. Please choose another account and try again, or authenticate {{ accountId }} using {{ authCommand }}."
|
|
611
643
|
add:
|
|
612
644
|
describe: "Create a new component within a project."
|
|
613
645
|
options:
|
|
@@ -0,0 +1,7 @@
|
|
|
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 downloadProjectFiles(derivedAccountId: number, projectName: string, buildId: number, projectDest: string): Promise<void>;
|
|
5
|
+
export declare function migrateApp2025_2(derivedAccountId: number, options: ArgumentsCamelCase<MigrateAppOptions>): Promise<void>;
|
|
6
|
+
export declare function logInvalidAccountError(i18nKey: string): void;
|
|
7
|
+
export declare function migrateApp2023_2(derivedAccountId: number, options: ArgumentsCamelCase<MigrateAppOptions>, accountConfig: CLIAccount): Promise<void>;
|
|
@@ -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 {
|
|
@@ -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,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.4.1-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.
|
|
8
|
+
"@hubspot/local-dev-lib": "0.3.0-experimental.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",
|
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
|
+
};
|