@hubspot/cli 7.4.9-experimental.0 → 7.5.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/api/migrate.d.ts +2 -1
- package/api/migrate.js +7 -0
- package/bin/cli.js +6 -183
- package/commands/project/migrate.d.ts +8 -0
- package/commands/project/migrate.js +48 -0
- package/commands/project.js +2 -0
- package/lang/en.js +0 -2
- package/lang/en.lyaml +7 -1
- package/lib/app/migrate.d.ts +2 -2
- package/lib/app/migrate.js +71 -31
- package/lib/app/migrate_legacy.js +5 -3
- package/lib/middleware/__test__/configMiddleware.test.d.ts +1 -0
- package/lib/middleware/__test__/configMiddleware.test.js +194 -0
- package/lib/middleware/__test__/gitMiddleware.test.d.ts +1 -0
- package/lib/middleware/__test__/gitMiddleware.test.js +76 -0
- package/lib/middleware/__test__/notificationsMiddleware.test.d.ts +1 -0
- package/lib/middleware/__test__/notificationsMiddleware.test.js +10 -0
- package/lib/middleware/__test__/requestMiddleware.test.d.ts +1 -0
- package/lib/middleware/__test__/requestMiddleware.test.js +20 -0
- package/lib/middleware/__test__/utils.test.d.ts +1 -0
- package/lib/middleware/__test__/utils.test.js +53 -0
- package/lib/middleware/__test__/yargsChecksMiddleware.test.d.ts +1 -0
- package/lib/middleware/__test__/yargsChecksMiddleware.test.js +81 -0
- package/lib/middleware/configMiddleware.d.ts +13 -0
- package/lib/middleware/configMiddleware.js +105 -0
- package/lib/middleware/gitMiddleware.d.ts +2 -0
- package/lib/middleware/gitMiddleware.js +14 -0
- package/lib/middleware/notificationsMiddleware.d.ts +1 -0
- package/lib/middleware/notificationsMiddleware.js +38 -0
- package/lib/middleware/requestMiddleware.d.ts +1 -0
- package/lib/middleware/requestMiddleware.js +11 -0
- package/lib/middleware/utils.d.ts +8 -0
- package/lib/middleware/utils.js +17 -0
- package/lib/middleware/yargsChecksMiddleware.d.ts +4 -0
- package/lib/middleware/yargsChecksMiddleware.js +24 -0
- package/lib/projects/index.d.ts +3 -2
- package/package.json +2 -2
- package/types/Yargs.d.ts +6 -3
package/api/migrate.d.ts
CHANGED
|
@@ -50,10 +50,11 @@ export interface MigrationSuccess extends MigrationBaseStatus {
|
|
|
50
50
|
}
|
|
51
51
|
export interface MigrationFailed extends MigrationBaseStatus {
|
|
52
52
|
status: typeof MIGRATION_STATUS.FAILURE;
|
|
53
|
-
|
|
53
|
+
projectErrorDetail: string;
|
|
54
54
|
componentErrorDetails: Record<string, string>;
|
|
55
55
|
}
|
|
56
56
|
export type MigrationStatus = MigrationInProgress | MigrationInputRequired | MigrationSuccess | MigrationFailed;
|
|
57
|
+
export declare function isMigrationStatus(error: unknown): error is MigrationStatus;
|
|
57
58
|
export declare function listAppsForMigration(accountId: number): HubSpotPromise<ListAppsResponse>;
|
|
58
59
|
export declare function initializeMigration(accountId: number, applicationId: number, platformVersion: string): HubSpotPromise<InitializeMigrationResponse>;
|
|
59
60
|
export declare function continueMigration(portalId: number, migrationId: number, componentUids: Record<string, string>, projectName: string): HubSpotPromise<ContinueMigrationResponse>;
|
package/api/migrate.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isMigrationStatus = isMigrationStatus;
|
|
3
4
|
exports.listAppsForMigration = listAppsForMigration;
|
|
4
5
|
exports.initializeMigration = initializeMigration;
|
|
5
6
|
exports.continueMigration = continueMigration;
|
|
@@ -7,6 +8,12 @@ exports.checkMigrationStatusV2 = checkMigrationStatusV2;
|
|
|
7
8
|
const projects_1 = require("@hubspot/local-dev-lib/constants/projects");
|
|
8
9
|
const http_1 = require("@hubspot/local-dev-lib/http");
|
|
9
10
|
const MIGRATIONS_API_PATH_V2 = 'dfs/migrations/v2';
|
|
11
|
+
function isMigrationStatus(error) {
|
|
12
|
+
return (typeof error === 'object' &&
|
|
13
|
+
error !== null &&
|
|
14
|
+
'id' in error &&
|
|
15
|
+
'status' in error);
|
|
16
|
+
}
|
|
10
17
|
async function listAppsForMigration(accountId) {
|
|
11
18
|
return http_1.http.get(accountId, {
|
|
12
19
|
url: `${MIGRATIONS_API_PATH_V2}/list-apps`,
|
package/bin/cli.js
CHANGED
|
@@ -1,21 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
const yargs = require('yargs');
|
|
4
|
-
const updateNotifier = require('update-notifier');
|
|
5
|
-
const chalk = require('chalk');
|
|
6
4
|
const { logger } = require('@hubspot/local-dev-lib/logger');
|
|
7
|
-
const { addUserAgentHeader } = require('@hubspot/local-dev-lib/http');
|
|
8
|
-
const { loadConfig, getAccountId, configFileExists, getConfigPath, validateConfig, } = require('@hubspot/local-dev-lib/config');
|
|
9
5
|
const { logError } = require('../lib/errorHandlers/index');
|
|
10
6
|
const { setLogLevel, getCommandName } = require('../lib/commonOpts');
|
|
11
|
-
const { validateAccount } = require('../lib/validation');
|
|
12
7
|
const { trackHelpUsage, trackConvertFieldsUsage, } = require('../lib/usageTracking');
|
|
13
|
-
const { getIsInProject } = require('../lib/projects');
|
|
14
|
-
const pkg = require('../package.json');
|
|
15
|
-
const { i18n } = require('../lib/lang');
|
|
16
8
|
const { EXIT_CODES } = require('../lib/enums/exitCodes');
|
|
17
|
-
const {
|
|
18
|
-
const {
|
|
9
|
+
const { loadConfigMiddleware, injectAccountIdMiddleware, validateAccountOptions, handleDeprecatedEnvVariables, } = require('../lib/middleware/configMiddleware');
|
|
10
|
+
const { notifyAboutUpdates, } = require('../lib/middleware/notificationsMiddleware');
|
|
11
|
+
const { checkAndWarnGitInclusionMiddleware, } = require('../lib/middleware/gitMiddleware');
|
|
12
|
+
const { performChecks } = require('../lib/middleware/yargsChecksMiddleware');
|
|
13
|
+
const { setRequestHeaders } = require('../lib/middleware/requestMiddleware');
|
|
19
14
|
const removeCommand = require('../commands/remove');
|
|
20
15
|
const initCommand = require('../commands/init');
|
|
21
16
|
const logsCommand = require('../commands/logs');
|
|
@@ -44,33 +39,7 @@ const feedbackCommand = require('../commands/feedback');
|
|
|
44
39
|
const doctorCommand = require('../commands/doctor');
|
|
45
40
|
const completionCommand = require('../commands/completion');
|
|
46
41
|
const appCommand = require('../commands/app');
|
|
47
|
-
|
|
48
|
-
pkg: { ...pkg, name: '@hubspot/cli' },
|
|
49
|
-
distTag: 'latest',
|
|
50
|
-
shouldNotifyInNpmScript: true,
|
|
51
|
-
});
|
|
52
|
-
const CMS_CLI_PACKAGE_NAME = '@hubspot/cms-cli';
|
|
53
|
-
notifier.notify({
|
|
54
|
-
message: pkg.name === CMS_CLI_PACKAGE_NAME
|
|
55
|
-
? i18n(`commands.generalErrors.updateNotify.cmsUpdateNotification`, {
|
|
56
|
-
packageName: CMS_CLI_PACKAGE_NAME,
|
|
57
|
-
updateCommand: uiCommandReference('{updateCommand}'),
|
|
58
|
-
})
|
|
59
|
-
: i18n(`commands.generalErrors.updateNotify.cliUpdateNotification`, {
|
|
60
|
-
updateCommand: uiCommandReference('{updateCommand}'),
|
|
61
|
-
}),
|
|
62
|
-
defer: false,
|
|
63
|
-
boxenOptions: {
|
|
64
|
-
borderColor: UI_COLORS.MARIGOLD_DARK,
|
|
65
|
-
margin: 1,
|
|
66
|
-
padding: 1,
|
|
67
|
-
textAlignment: 'center',
|
|
68
|
-
borderStyle: 'round',
|
|
69
|
-
title: pkg.name === CMS_CLI_PACKAGE_NAME
|
|
70
|
-
? null
|
|
71
|
-
: chalk.bold(i18n(`commands.generalErrors.updateNotify.notifyTitle`)),
|
|
72
|
-
},
|
|
73
|
-
});
|
|
42
|
+
notifyAboutUpdates();
|
|
74
43
|
const getTerminalWidth = () => {
|
|
75
44
|
const width = yargs.terminalWidth();
|
|
76
45
|
if (width >= 100)
|
|
@@ -92,152 +61,6 @@ const handleFailure = (msg, err, yargs) => {
|
|
|
92
61
|
process.exit(EXIT_CODES.ERROR);
|
|
93
62
|
}
|
|
94
63
|
};
|
|
95
|
-
const performChecks = argv => {
|
|
96
|
-
// "hs config set default-account" has moved to "hs accounts use"
|
|
97
|
-
if (argv._[0] === 'config' &&
|
|
98
|
-
argv._[1] === 'set' &&
|
|
99
|
-
argv._[2] === 'default-account') {
|
|
100
|
-
logger.error(i18n(`commands.generalErrors.setDefaultAccountMoved`));
|
|
101
|
-
process.exit(EXIT_CODES.ERROR);
|
|
102
|
-
}
|
|
103
|
-
// Require "project" command when running upload/watch inside of a project
|
|
104
|
-
if (argv._.length === 1 && ['upload', 'watch'].includes(argv._[0])) {
|
|
105
|
-
if (getIsInProject(argv.src)) {
|
|
106
|
-
logger.error(i18n(`commands.generalErrors.srcIsProject`, {
|
|
107
|
-
src: argv.src || './',
|
|
108
|
-
command: argv._.join(' '),
|
|
109
|
-
}));
|
|
110
|
-
process.exit(EXIT_CODES.ERROR);
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
return true;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
return true;
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
const setRequestHeaders = () => {
|
|
121
|
-
addUserAgentHeader('HubSpot CLI', pkg.version);
|
|
122
|
-
};
|
|
123
|
-
const isTargetedCommand = (options, commandMap) => {
|
|
124
|
-
const checkCommand = (options, commandMap) => {
|
|
125
|
-
const currentCommand = options._[0];
|
|
126
|
-
if (!commandMap[currentCommand]) {
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
if (commandMap[currentCommand].target) {
|
|
130
|
-
return true;
|
|
131
|
-
}
|
|
132
|
-
const subCommands = commandMap[currentCommand].subCommands || {};
|
|
133
|
-
if (options._.length > 1) {
|
|
134
|
-
return checkCommand({ _: options._.slice(1) }, subCommands);
|
|
135
|
-
}
|
|
136
|
-
return false;
|
|
137
|
-
};
|
|
138
|
-
return checkCommand(options, commandMap);
|
|
139
|
-
};
|
|
140
|
-
const SKIP_CONFIG_VALIDATION = {
|
|
141
|
-
init: { target: true },
|
|
142
|
-
auth: { target: true },
|
|
143
|
-
};
|
|
144
|
-
const handleDeprecatedEnvVariables = options => {
|
|
145
|
-
// HUBSPOT_PORTAL_ID is deprecated, but we'll still support it for now
|
|
146
|
-
// The HubSpot GH Deploy Action still uses HUBSPOT_PORTAL_ID
|
|
147
|
-
if (options.useEnv &&
|
|
148
|
-
process.env.HUBSPOT_PORTAL_ID &&
|
|
149
|
-
!process.env.HUBSPOT_ACCOUNT_ID) {
|
|
150
|
-
uiDeprecatedTag(i18n(`commands.generalErrors.handleDeprecatedEnvVariables.portalEnvVarDeprecated`, {
|
|
151
|
-
configPath: getConfigPath(),
|
|
152
|
-
}));
|
|
153
|
-
process.env.HUBSPOT_ACCOUNT_ID = process.env.HUBSPOT_PORTAL_ID;
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
/**
|
|
157
|
-
* Auto-injects the derivedAccountId flag into all commands
|
|
158
|
-
*/
|
|
159
|
-
const injectAccountIdMiddleware = async (options) => {
|
|
160
|
-
const { account } = options;
|
|
161
|
-
// Preserves the original --account flag for certain commands.
|
|
162
|
-
options.providedAccountId = account;
|
|
163
|
-
if (options.useEnv && process.env.HUBSPOT_ACCOUNT_ID) {
|
|
164
|
-
options.derivedAccountId = parseInt(process.env.HUBSPOT_ACCOUNT_ID, 10);
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
options.derivedAccountId = getAccountId(account);
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
const loadConfigMiddleware = async (options) => {
|
|
171
|
-
// Skip this when no command is provided
|
|
172
|
-
if (!options._.length) {
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
const maybeValidateConfig = () => {
|
|
176
|
-
if (!isTargetedCommand(options, SKIP_CONFIG_VALIDATION) &&
|
|
177
|
-
!validateConfig()) {
|
|
178
|
-
process.exit(EXIT_CODES.ERROR);
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
if (configFileExists(true) && options.config) {
|
|
182
|
-
logger.error(i18n(`commands.generalErrors.loadConfigMiddleware.configFileExists`, {
|
|
183
|
-
configPath: getConfigPath(),
|
|
184
|
-
}));
|
|
185
|
-
process.exit(EXIT_CODES.ERROR);
|
|
186
|
-
}
|
|
187
|
-
else if (!isTargetedCommand(options, { init: { target: true } })) {
|
|
188
|
-
const { config: configPath } = options;
|
|
189
|
-
const config = loadConfig(configPath, options);
|
|
190
|
-
// We don't run validateConfig() for auth because users should be able to run it when
|
|
191
|
-
// no accounts are configured, but we still want to exit if the config file is not found
|
|
192
|
-
if (isTargetedCommand(options, { auth: { target: true } }) && !config) {
|
|
193
|
-
process.exit(EXIT_CODES.ERROR);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
maybeValidateConfig();
|
|
197
|
-
};
|
|
198
|
-
const checkAndWarnGitInclusionMiddleware = options => {
|
|
199
|
-
// Skip this when no command is provided
|
|
200
|
-
if (!options._.length) {
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
checkAndWarnGitInclusion(getConfigPath());
|
|
204
|
-
};
|
|
205
|
-
const accountsSubCommands = {
|
|
206
|
-
target: false,
|
|
207
|
-
subCommands: {
|
|
208
|
-
clean: { target: true },
|
|
209
|
-
list: { target: true },
|
|
210
|
-
ls: { target: true },
|
|
211
|
-
remove: { target: true },
|
|
212
|
-
},
|
|
213
|
-
};
|
|
214
|
-
const sandboxesSubCommands = {
|
|
215
|
-
target: false,
|
|
216
|
-
subCommands: {
|
|
217
|
-
delete: { target: true },
|
|
218
|
-
},
|
|
219
|
-
};
|
|
220
|
-
const SKIP_ACCOUNT_VALIDATION = {
|
|
221
|
-
init: { target: true },
|
|
222
|
-
auth: { target: true },
|
|
223
|
-
account: accountsSubCommands,
|
|
224
|
-
accounts: accountsSubCommands,
|
|
225
|
-
sandbox: sandboxesSubCommands,
|
|
226
|
-
sandboxes: sandboxesSubCommands,
|
|
227
|
-
};
|
|
228
|
-
const validateAccountOptions = async (options) => {
|
|
229
|
-
// Skip this when no command is provided
|
|
230
|
-
if (!options._.length) {
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
let validAccount = true;
|
|
234
|
-
if (!isTargetedCommand(options, SKIP_ACCOUNT_VALIDATION)) {
|
|
235
|
-
validAccount = await validateAccount(options);
|
|
236
|
-
}
|
|
237
|
-
if (!validAccount) {
|
|
238
|
-
process.exit(EXIT_CODES.ERROR);
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
64
|
const argv = yargs
|
|
242
65
|
.usage('The command line interface to interact with HubSpot.')
|
|
243
66
|
// loadConfigMiddleware loads the new hidden config for all commands
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ArgumentsCamelCase, Argv, CommandModule } from 'yargs';
|
|
2
|
+
import { ProjectMigrateOptions } from '../../types/Yargs';
|
|
3
|
+
export declare const command = "migrate";
|
|
4
|
+
export declare const describe: undefined;
|
|
5
|
+
export declare function handler(options: ArgumentsCamelCase<ProjectMigrateOptions>): Promise<undefined>;
|
|
6
|
+
export declare function builder(yargs: Argv): Argv<ProjectMigrateOptions>;
|
|
7
|
+
declare const migrateAppCommand: CommandModule<unknown, ProjectMigrateOptions>;
|
|
8
|
+
export default migrateAppCommand;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.describe = exports.command = void 0;
|
|
4
|
+
exports.handler = handler;
|
|
5
|
+
exports.builder = builder;
|
|
6
|
+
const lang_1 = require("../../lib/lang");
|
|
7
|
+
const logger_1 = require("@hubspot/local-dev-lib/logger");
|
|
8
|
+
const commonOpts_1 = require("../../lib/commonOpts");
|
|
9
|
+
const migrate_1 = require("../../lib/app/migrate");
|
|
10
|
+
const projects_1 = require("../../lib/projects");
|
|
11
|
+
const projects_2 = require("@hubspot/local-dev-lib/constants/projects");
|
|
12
|
+
const errorHandlers_1 = require("../../lib/errorHandlers");
|
|
13
|
+
const exitCodes_1 = require("../../lib/enums/exitCodes");
|
|
14
|
+
exports.command = 'migrate';
|
|
15
|
+
exports.describe = undefined; // i18n('commands.project.subcommands.migrate.noProjectConfig')
|
|
16
|
+
async function handler(options) {
|
|
17
|
+
const projectConfig = await (0, projects_1.getProjectConfig)();
|
|
18
|
+
if (!projectConfig) {
|
|
19
|
+
logger_1.logger.error((0, lang_1.i18n)('commands.project.subcommands.migrate.errors.noProjectConfig'));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const { derivedAccountId } = options;
|
|
23
|
+
try {
|
|
24
|
+
await (0, migrate_1.migrateApp2025_2)(derivedAccountId, {
|
|
25
|
+
...options,
|
|
26
|
+
name: projectConfig?.projectConfig?.name,
|
|
27
|
+
platformVersion: projects_2.PLATFORM_VERSIONS.unstable,
|
|
28
|
+
}, projectConfig);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
(0, errorHandlers_1.logError)(error);
|
|
32
|
+
return process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
33
|
+
}
|
|
34
|
+
return process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
35
|
+
}
|
|
36
|
+
function builder(yargs) {
|
|
37
|
+
(0, commonOpts_1.addConfigOptions)(yargs);
|
|
38
|
+
(0, commonOpts_1.addAccountOptions)(yargs);
|
|
39
|
+
(0, commonOpts_1.addGlobalOptions)(yargs);
|
|
40
|
+
return yargs;
|
|
41
|
+
}
|
|
42
|
+
const migrateAppCommand = {
|
|
43
|
+
command: exports.command,
|
|
44
|
+
describe: exports.describe,
|
|
45
|
+
handler,
|
|
46
|
+
builder,
|
|
47
|
+
};
|
|
48
|
+
exports.default = migrateAppCommand;
|
package/commands/project.js
CHANGED
|
@@ -15,6 +15,7 @@ const open = require('./project/open');
|
|
|
15
15
|
const dev = require('./project/dev');
|
|
16
16
|
const add = require('./project/add');
|
|
17
17
|
const migrateApp = require('./project/migrateApp');
|
|
18
|
+
const migrate = require('./project/migrate');
|
|
18
19
|
const cloneApp = require('./project/cloneApp');
|
|
19
20
|
const installDeps = require('./project/installDeps');
|
|
20
21
|
const i18nKey = 'commands.project';
|
|
@@ -34,6 +35,7 @@ exports.builder = yargs => {
|
|
|
34
35
|
.command(download)
|
|
35
36
|
.command(open)
|
|
36
37
|
.command(migrateApp)
|
|
38
|
+
.command(migrate)
|
|
37
39
|
.command(cloneApp)
|
|
38
40
|
.command(installDeps)
|
|
39
41
|
.demandCommand(1, '');
|
package/lang/en.js
CHANGED
|
@@ -11,8 +11,6 @@ export const commands = {
|
|
|
11
11
|
},
|
|
12
12
|
srcIsProject: (src, command) =>
|
|
13
13
|
`"${src}" is in a project folder. Did you mean "hs project ${command}"?`,
|
|
14
|
-
setDefaultAccountMoved:
|
|
15
|
-
'This command has moved. Try `hs accounts use` instead',
|
|
16
14
|
handleDeprecatedEnvVariables: {
|
|
17
15
|
portalEnvVarDeprecated:
|
|
18
16
|
'The HUBSPOT_PORTAL_ID environment variable is deprecated. Please use HUBSPOT_ACCOUNT_ID instead.',
|
package/lang/en.lyaml
CHANGED
|
@@ -6,7 +6,6 @@ en:
|
|
|
6
6
|
cmsUpdateNotification: "{{#bold}}The CMS CLI is now the HubSpot CLI{{/bold}}\n\nTo upgrade, uninstall {{#bold}}{{ packageName }}{{/bold}}\nand then run {{ updateCommand }}"
|
|
7
7
|
cliUpdateNotification: "HubSpot CLI version {{#cyan}}{{#bold}}{currentVersion}{{/bold}}{{/cyan}} is outdated.\nRun {{ updateCommand }} to upgrade to version {{#cyan}}{{#bold}}{latestVersion}{{/bold}}{{/cyan}}"
|
|
8
8
|
srcIsProject: "\"{{ src }}\" is in a project folder. Did you mean \"hs project {{command}}\"?"
|
|
9
|
-
setDefaultAccountMoved: "This command has moved. Try `hs accounts use` instead"
|
|
10
9
|
handleDeprecatedEnvVariables:
|
|
11
10
|
portalEnvVarDeprecated: "The HUBSPOT_PORTAL_ID environment variable is deprecated. Please use HUBSPOT_ACCOUNT_ID instead."
|
|
12
11
|
loadConfigMiddleware:
|
|
@@ -589,6 +588,7 @@ en:
|
|
|
589
588
|
componentsToBeMigrated: "The following component types will be migrated: {{ components }}"
|
|
590
589
|
componentsThatWillNotBeMigrated: "[NOTE] These component types are not yet supported for migration but will be available later: {{ components }}"
|
|
591
590
|
errors:
|
|
591
|
+
noAppsForProject: "No apps associated with project {{ projectName }}"
|
|
592
592
|
noAppsEligible: "No apps in account {{ accountId }} are currently migratable"
|
|
593
593
|
noAccountConfig: "There is no account associated with {{ accountId }} in the config file. Please choose another account and try again, or authenticate {{ accountId }} using {{ authCommand }}."
|
|
594
594
|
invalidAccountTypeTitle: "{{#bold}}Developer account not targeted{{/bold}}"
|
|
@@ -656,6 +656,12 @@ en:
|
|
|
656
656
|
examples:
|
|
657
657
|
default: "Create a component within your project"
|
|
658
658
|
withFlags: "Use --name and --type flags to bypass the prompt."
|
|
659
|
+
migrate:
|
|
660
|
+
describe: "Migrate a project to the projects framework."
|
|
661
|
+
errors:
|
|
662
|
+
noProjectConfig: "No project detected. Please run this command again from a project directory."
|
|
663
|
+
examples:
|
|
664
|
+
default: "Migrate a project to the projects framework"
|
|
659
665
|
deploy:
|
|
660
666
|
describe: "Deploy a project build."
|
|
661
667
|
deployBuildIdPrompt: "[--build] Deploy which build?"
|
package/lib/app/migrate.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ArgumentsCamelCase } from 'yargs';
|
|
2
|
+
import { LoadedProjectConfig } from '../projects';
|
|
2
3
|
import { MigrateAppOptions } from '../../types/Yargs';
|
|
3
|
-
export declare function
|
|
4
|
-
export declare function migrateApp2025_2(derivedAccountId: number, options: ArgumentsCamelCase<MigrateAppOptions>): Promise<void>;
|
|
4
|
+
export declare function migrateApp2025_2(derivedAccountId: number, options: ArgumentsCamelCase<MigrateAppOptions>, projectConfig?: LoadedProjectConfig): Promise<void>;
|
|
5
5
|
export declare function logInvalidAccountError(i18nKey: string): void;
|
package/lib/app/migrate.js
CHANGED
|
@@ -3,7 +3,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.downloadProjectFiles = downloadProjectFiles;
|
|
7
6
|
exports.migrateApp2025_2 = migrateApp2025_2;
|
|
8
7
|
exports.logInvalidAccountError = logInvalidAccountError;
|
|
9
8
|
const logger_1 = require("@hubspot/local-dev-lib/logger");
|
|
@@ -23,6 +22,7 @@ const projects_3 = require("../projects");
|
|
|
23
22
|
const SpinniesManager_1 = __importDefault(require("../ui/SpinniesManager"));
|
|
24
23
|
const polling_1 = require("../polling");
|
|
25
24
|
const migrate_1 = require("../../api/migrate");
|
|
25
|
+
const fs_1 = __importDefault(require("fs"));
|
|
26
26
|
function getUnmigratableReason(reasonCode) {
|
|
27
27
|
switch (reasonCode) {
|
|
28
28
|
case projects_1.UNMIGRATABLE_REASONS.UP_TO_DATE:
|
|
@@ -37,16 +37,32 @@ function getUnmigratableReason(reasonCode) {
|
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
function filterAppsByProjectName(projectConfig) {
|
|
41
|
+
return (app) => {
|
|
42
|
+
if (projectConfig) {
|
|
43
|
+
return app.projectName === projectConfig?.projectConfig?.name;
|
|
44
|
+
}
|
|
45
|
+
return !app.projectName;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async function handleMigrationSetup(derivedAccountId, options, projectConfig) {
|
|
41
49
|
const { name, dest, appId } = options;
|
|
42
|
-
const { data } = await (0, migrate_1.listAppsForMigration)(derivedAccountId);
|
|
43
|
-
const
|
|
44
|
-
const
|
|
50
|
+
const { data: { migratableApps, unmigratableApps }, } = await (0, migrate_1.listAppsForMigration)(derivedAccountId);
|
|
51
|
+
const filteredMigratableApps = migratableApps.filter(filterAppsByProjectName(projectConfig));
|
|
52
|
+
const filteredUnmigratableApps = unmigratableApps.filter(filterAppsByProjectName(projectConfig));
|
|
53
|
+
const allApps = [...filteredMigratableApps, ...filteredUnmigratableApps];
|
|
54
|
+
if (allApps.length > 1 && projectConfig) {
|
|
55
|
+
throw new Error('Multiple apps found in project, this is not allowed in the new system');
|
|
56
|
+
}
|
|
45
57
|
if (allApps.length === 0) {
|
|
46
|
-
const reasons =
|
|
58
|
+
const reasons = filteredUnmigratableApps.map(app => `${chalk_1.default.bold(app.appName)}: ${getUnmigratableReason(app.unmigratableReason)}`);
|
|
59
|
+
if (projectConfig) {
|
|
60
|
+
// TODO: i18n, get copy from UX
|
|
61
|
+
throw new Error('No migratable apps in project');
|
|
62
|
+
}
|
|
47
63
|
throw new Error(`${(0, lang_1.i18n)(`commands.project.subcommands.migrateApp.errors.noAppsEligible`, {
|
|
48
|
-
accountId: derivedAccountId,
|
|
49
|
-
})}
|
|
64
|
+
accountId: (0, ui_1.uiAccountDescription)(derivedAccountId),
|
|
65
|
+
})}${reasons.length ? `\n - ${reasons.join('\n - ')}` : ''}`);
|
|
50
66
|
}
|
|
51
67
|
if (appId &&
|
|
52
68
|
!allApps.some(app => {
|
|
@@ -98,6 +114,16 @@ async function handleMigrationSetup(derivedAccountId, options) {
|
|
|
98
114
|
if (!proceed) {
|
|
99
115
|
return {};
|
|
100
116
|
}
|
|
117
|
+
// If it's a project we don't want to prompt for dest and name, so just return early
|
|
118
|
+
if (projectConfig &&
|
|
119
|
+
projectConfig?.projectConfig &&
|
|
120
|
+
projectConfig?.projectDir) {
|
|
121
|
+
return {
|
|
122
|
+
appIdToMigrate,
|
|
123
|
+
projectName: projectConfig.projectConfig.name,
|
|
124
|
+
projectDest: projectConfig.projectDir,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
101
127
|
const projectName = name ||
|
|
102
128
|
(await (0, promptUtils_1.inputPrompt)((0, lang_1.i18n)('commands.project.subcommands.migrateApp.prompt.inputName')));
|
|
103
129
|
const { projectExists } = await (0, projects_3.ensureProjectExists)(derivedAccountId, projectName, { allowCreate: false, noLogs: true });
|
|
@@ -133,8 +159,8 @@ async function beginMigration(derivedAccountId, appId, platformVersion) {
|
|
|
133
159
|
const { componentHint, componentType } = component;
|
|
134
160
|
uidMap[componentId] = await (0, promptUtils_1.inputPrompt)((0, lang_1.i18n)('commands.project.subcommands.migrateApp.prompt.uidForComponent', {
|
|
135
161
|
componentName: componentHint
|
|
136
|
-
? `${
|
|
137
|
-
: componentType,
|
|
162
|
+
? `${(0, transform_1.mapToUserFacingType)(componentType)} '${componentHint}'`
|
|
163
|
+
: (0, transform_1.mapToUserFacingType)(componentType),
|
|
138
164
|
}), {
|
|
139
165
|
validate: (uid) => {
|
|
140
166
|
const result = (0, project_parsing_lib_1.validateUid)(uid);
|
|
@@ -169,37 +195,46 @@ async function finalizeMigration(derivedAccountId, migrationId, uidMap, projectN
|
|
|
169
195
|
SpinniesManager_1.default.fail('finishingMigration', {
|
|
170
196
|
text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.migrationFailed`),
|
|
171
197
|
});
|
|
172
|
-
|
|
198
|
+
if ((0, migrate_1.isMigrationStatus)(error) && error.status === Migration_1.MIGRATION_STATUS.FAILURE) {
|
|
199
|
+
throw new Error(error.projectErrorDetail);
|
|
200
|
+
}
|
|
201
|
+
throw new Error((0, lang_1.i18n)('commands.project.subcommands.migrateApp.errors.migrationFailed'), {
|
|
202
|
+
cause: error,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
if (pollResponse.status !== Migration_1.MIGRATION_STATUS.SUCCESS) {
|
|
206
|
+
throw new Error((0, lang_1.i18n)('commands.project.subcommands.migrateApp.errors.migrationFailed'));
|
|
173
207
|
}
|
|
174
208
|
if (pollResponse.status === Migration_1.MIGRATION_STATUS.SUCCESS) {
|
|
175
209
|
SpinniesManager_1.default.succeed('finishingMigration', {
|
|
176
210
|
text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.migrationComplete`),
|
|
177
211
|
});
|
|
178
|
-
return pollResponse.buildId;
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
SpinniesManager_1.default.fail('finishingMigration', {
|
|
182
|
-
text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.migrationFailed`),
|
|
183
|
-
});
|
|
184
|
-
if (pollResponse.status === Migration_1.MIGRATION_STATUS.FAILURE) {
|
|
185
|
-
logger_1.logger.error(pollResponse.componentErrorDetails);
|
|
186
|
-
throw new Error(pollResponse.projectErrorsDetail);
|
|
187
|
-
}
|
|
188
|
-
throw new Error((0, lang_1.i18n)('commands.project.subcommands.migrateApp.errors.migrationFailed'));
|
|
189
212
|
}
|
|
213
|
+
return pollResponse.buildId;
|
|
190
214
|
}
|
|
191
|
-
async function downloadProjectFiles(derivedAccountId, projectName, buildId, projectDest) {
|
|
215
|
+
async function downloadProjectFiles(derivedAccountId, projectName, buildId, projectDest, projectConfig) {
|
|
192
216
|
try {
|
|
193
217
|
SpinniesManager_1.default.add('fetchingMigratedProject', {
|
|
194
218
|
text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.downloadingProjectContents`),
|
|
195
219
|
});
|
|
196
220
|
const { data: zippedProject } = await (0, projects_2.downloadProject)(derivedAccountId, projectName, buildId);
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
221
|
+
let absoluteDestPath;
|
|
222
|
+
if (projectConfig?.projectConfig && projectConfig?.projectDir) {
|
|
223
|
+
const { projectDir } = projectConfig;
|
|
224
|
+
absoluteDestPath = projectDir;
|
|
225
|
+
const { srcDir } = projectConfig.projectConfig;
|
|
226
|
+
const archiveDest = path_1.default.join(projectDir, 'archive');
|
|
227
|
+
// Move the existing source directory to archive
|
|
228
|
+
fs_1.default.renameSync(path_1.default.join(projectDir, srcDir), archiveDest);
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
absoluteDestPath = projectDest
|
|
232
|
+
? path_1.default.resolve((0, path_2.getCwd)(), projectDest)
|
|
233
|
+
: (0, path_2.getCwd)();
|
|
234
|
+
}
|
|
200
235
|
await (0, archive_1.extractZipArchive)(zippedProject, (0, path_2.sanitizeFileName)(projectName), absoluteDestPath, {
|
|
201
236
|
includesRootDir: true,
|
|
202
|
-
hideLogs:
|
|
237
|
+
hideLogs: true,
|
|
203
238
|
});
|
|
204
239
|
SpinniesManager_1.default.succeed('fetchingMigratedProject', {
|
|
205
240
|
text: (0, lang_1.i18n)(`commands.project.subcommands.migrateApp.spinners.downloadingProjectContentsComplete`),
|
|
@@ -213,9 +248,14 @@ async function downloadProjectFiles(derivedAccountId, projectName, buildId, proj
|
|
|
213
248
|
throw error;
|
|
214
249
|
}
|
|
215
250
|
}
|
|
216
|
-
async function migrateApp2025_2(derivedAccountId, options) {
|
|
251
|
+
async function migrateApp2025_2(derivedAccountId, options, projectConfig) {
|
|
217
252
|
SpinniesManager_1.default.init();
|
|
218
|
-
|
|
253
|
+
if (projectConfig &&
|
|
254
|
+
(!projectConfig?.projectConfig || !projectConfig?.projectDir)) {
|
|
255
|
+
// TODO: i18n
|
|
256
|
+
throw new Error('Invalid project config');
|
|
257
|
+
}
|
|
258
|
+
const { appIdToMigrate, projectName, projectDest } = await handleMigrationSetup(derivedAccountId, options, projectConfig);
|
|
219
259
|
if (!appIdToMigrate || !projectName || !projectDest) {
|
|
220
260
|
return;
|
|
221
261
|
}
|
|
@@ -224,8 +264,8 @@ async function migrateApp2025_2(derivedAccountId, options) {
|
|
|
224
264
|
return;
|
|
225
265
|
}
|
|
226
266
|
const { migrationId, uidMap } = migrationInProgress;
|
|
227
|
-
const buildId = await finalizeMigration(derivedAccountId, migrationId, uidMap, projectName);
|
|
228
|
-
await downloadProjectFiles(derivedAccountId, projectName, buildId, projectDest);
|
|
267
|
+
const buildId = await finalizeMigration(derivedAccountId, migrationId, uidMap, projectConfig?.projectConfig?.name || projectName);
|
|
268
|
+
await downloadProjectFiles(derivedAccountId, projectName, buildId, projectDest, projectConfig);
|
|
229
269
|
}
|
|
230
270
|
function logInvalidAccountError(i18nKey) {
|
|
231
271
|
(0, ui_1.uiLine)();
|
|
@@ -31,13 +31,15 @@ async function migrateApp2023_2(derivedAccountId, options, accountConfig) {
|
|
|
31
31
|
(0, migrate_1.logInvalidAccountError)('commands.project.subcommands.migrateApp');
|
|
32
32
|
process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
: await (0, selectPublicAppPrompt_1.selectPublicAppPrompt)({
|
|
34
|
+
let appId = options.appId;
|
|
35
|
+
if (!appId) {
|
|
36
|
+
const { appId: selectAppId } = await (0, selectPublicAppPrompt_1.selectPublicAppPrompt)({
|
|
37
37
|
accountId: derivedAccountId,
|
|
38
38
|
accountName,
|
|
39
39
|
isMigratingApp: true,
|
|
40
40
|
});
|
|
41
|
+
appId = selectAppId;
|
|
42
|
+
}
|
|
41
43
|
try {
|
|
42
44
|
const { data: selectedApp } = await (0, appsDev_1.fetchPublicAppMetadata)(appId, derivedAccountId);
|
|
43
45
|
// preventProjectMigrations returns true if we have not added app to allowlist config.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|