@hubspot/cli 5.2.1-beta.11 → 5.2.1-beta.13
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.
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
2
3
|
const {
|
|
3
4
|
addAccountOptions,
|
|
4
5
|
addConfigOptions,
|
|
@@ -12,8 +13,8 @@ const {
|
|
|
12
13
|
selectPublicAppPrompt,
|
|
13
14
|
} = require('../../lib/prompts/selectPublicAppPrompt');
|
|
14
15
|
const {
|
|
15
|
-
|
|
16
|
-
} = require('../../lib/prompts/
|
|
16
|
+
createProjectPrompt,
|
|
17
|
+
} = require('../../lib/prompts/createProjectPrompt');
|
|
17
18
|
const { poll } = require('../../lib/polling');
|
|
18
19
|
const {
|
|
19
20
|
uiLine,
|
|
@@ -27,6 +28,8 @@ const {
|
|
|
27
28
|
} = require('../../lib/errorHandlers/apiErrors');
|
|
28
29
|
const { EXIT_CODES } = require('../../lib/enums/exitCodes');
|
|
29
30
|
const { isAppDeveloperAccount } = require('../../lib/accountTypes');
|
|
31
|
+
const { writeProjectConfig } = require('../../lib/projects');
|
|
32
|
+
const { PROJECT_CONFIG_FILE } = require('../../lib/constants');
|
|
30
33
|
const {
|
|
31
34
|
cloneApp,
|
|
32
35
|
checkCloneStatus,
|
|
@@ -35,9 +38,6 @@ const {
|
|
|
35
38
|
const { getCwd } = require('@hubspot/local-dev-lib/path');
|
|
36
39
|
const { logger } = require('@hubspot/local-dev-lib/logger');
|
|
37
40
|
const { getAccountConfig } = require('@hubspot/local-dev-lib/config');
|
|
38
|
-
const {
|
|
39
|
-
fetchPublicAppMetadata,
|
|
40
|
-
} = require('@hubspot/local-dev-lib/api/appsDev');
|
|
41
41
|
const { extractZipArchive } = require('@hubspot/local-dev-lib/archive');
|
|
42
42
|
|
|
43
43
|
const i18nKey = 'commands.project.subcommands.cloneApp';
|
|
@@ -68,7 +68,7 @@ exports.handler = async options => {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
let appId;
|
|
71
|
-
let
|
|
71
|
+
let name;
|
|
72
72
|
let location;
|
|
73
73
|
try {
|
|
74
74
|
appId = options.appId;
|
|
@@ -77,16 +77,14 @@ exports.handler = async options => {
|
|
|
77
77
|
accountId,
|
|
78
78
|
accountName,
|
|
79
79
|
options,
|
|
80
|
-
|
|
80
|
+
isMigratingApp: false,
|
|
81
81
|
});
|
|
82
82
|
appId = appIdResponse.appId;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const locationResponse = await cloneAppLocationPrompt(options, appName);
|
|
89
|
-
location = locationResponse.location;
|
|
85
|
+
const projectResponse = await createProjectPrompt('', options, true);
|
|
86
|
+
name = projectResponse.name;
|
|
87
|
+
location = projectResponse.location;
|
|
90
88
|
} catch (error) {
|
|
91
89
|
logApiErrorInstance(error, new ApiErrorContext({ accountId }));
|
|
92
90
|
process.exit(EXIT_CODES.ERROR);
|
|
@@ -101,20 +99,37 @@ exports.handler = async options => {
|
|
|
101
99
|
const { exportId } = await cloneApp(accountId, appId);
|
|
102
100
|
const { status } = await poll(checkCloneStatus, accountId, exportId);
|
|
103
101
|
if (status === 'SUCCESS') {
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
102
|
+
// Ensure correct project folder structure exists
|
|
103
|
+
const baseDestPath = path.resolve(getCwd(), location);
|
|
104
|
+
const absoluteDestPath = path.resolve(baseDestPath, 'src', 'app');
|
|
105
|
+
fs.mkdirSync(absoluteDestPath, { recursive: true });
|
|
106
|
+
|
|
107
|
+
// Extract zipped app files and place them in correct directory
|
|
108
|
+
const zippedApp = await downloadClonedProject(accountId, exportId);
|
|
109
|
+
await extractZipArchive(zippedApp, name, absoluteDestPath, {
|
|
110
|
+
includesRootDir: true,
|
|
111
|
+
hideLogs: true,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Create hsproject.json file
|
|
115
|
+
const configPath = path.join(baseDestPath, PROJECT_CONFIG_FILE);
|
|
116
|
+
const configContent = {
|
|
117
|
+
name,
|
|
118
|
+
srcDir: 'src',
|
|
119
|
+
platformVersion: '2023.2',
|
|
120
|
+
};
|
|
121
|
+
const success = writeProjectConfig(configPath, configContent);
|
|
113
122
|
|
|
114
123
|
SpinniesManager.succeed('cloneApp', {
|
|
115
124
|
text: i18n(`${i18nKey}.cloneStatus.done`),
|
|
116
125
|
succeedColor: 'white',
|
|
117
126
|
});
|
|
127
|
+
if (!success) {
|
|
128
|
+
logger.error(
|
|
129
|
+
i18n(`${i18nKey}.errors.couldNotWriteConfigPath`),
|
|
130
|
+
configPath
|
|
131
|
+
);
|
|
132
|
+
}
|
|
118
133
|
logger.log('');
|
|
119
134
|
uiLine();
|
|
120
135
|
logger.success(i18n(`${i18nKey}.cloneStatus.success`, { location }));
|
|
@@ -79,13 +79,16 @@ exports.handler = async options => {
|
|
|
79
79
|
: await selectPublicAppPrompt({
|
|
80
80
|
accountId,
|
|
81
81
|
accountName,
|
|
82
|
-
|
|
82
|
+
isMigratingApp: true,
|
|
83
83
|
});
|
|
84
84
|
|
|
85
85
|
let appName;
|
|
86
86
|
try {
|
|
87
87
|
const selectedApp = await fetchPublicAppMetadata(appId, accountId);
|
|
88
|
-
if
|
|
88
|
+
// preventProjectMigrations returns true if we have not added app to allowlist config.
|
|
89
|
+
// listingInfo will only exist for marketplace apps
|
|
90
|
+
const { preventProjectMigrations, listingInfo } = selectedApp;
|
|
91
|
+
if (preventProjectMigrations && listingInfo) {
|
|
89
92
|
logger.error(i18n(`${i18nKey}.errors.invalidApp`, { appId }));
|
|
90
93
|
process.exit(EXIT_CODES.ERROR);
|
|
91
94
|
}
|
package/lang/en.lyaml
CHANGED
|
@@ -545,6 +545,7 @@ en:
|
|
|
545
545
|
errors:
|
|
546
546
|
invalidAccountTypeTitle: "{{#bold}}Developer account not targeted{{/bold}}"
|
|
547
547
|
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."
|
|
548
|
+
couldNotWriteConfigPath: "Failed to write project config at {{ configPath }}"
|
|
548
549
|
add:
|
|
549
550
|
describe: "Create a new component within a project"
|
|
550
551
|
options:
|
|
@@ -1244,12 +1245,6 @@ en:
|
|
|
1244
1245
|
noAppsCloneMessage: "The selected developer account {{#bold}}{{ accountName }}{{/bold}} doesn't have any apps that can be cloned to the projects framework."
|
|
1245
1246
|
errorFetchingApps: "There was an error fetching public apps."
|
|
1246
1247
|
cannotBeMigrated: "Cannot be migrated"
|
|
1247
|
-
cloneAppLocationPrompt:
|
|
1248
|
-
enterLocation: "[--location] Where should the cloned project be created?"
|
|
1249
|
-
errors:
|
|
1250
|
-
locationRequired: "A project location is required"
|
|
1251
|
-
invalidLocation: "The selected destination already exists. Please provide a new path for this project."
|
|
1252
|
-
invalidCharacters: "The selected destination contains invalid characters. Please provide a new path and try again."
|
|
1253
1248
|
downloadProjectPrompt:
|
|
1254
1249
|
selectProject: "Select a project to download:"
|
|
1255
1250
|
errors:
|
package/lib/projects.js
CHANGED
|
@@ -60,8 +60,10 @@ const writeProjectConfig = (configPath, config) => {
|
|
|
60
60
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
61
61
|
logger.debug(`Wrote project config at ${configPath}`);
|
|
62
62
|
} catch (e) {
|
|
63
|
-
logger.
|
|
63
|
+
logger.debug(e);
|
|
64
|
+
return false;
|
|
64
65
|
}
|
|
66
|
+
return true;
|
|
65
67
|
};
|
|
66
68
|
|
|
67
69
|
const getIsInProject = _dir => {
|
|
@@ -10,7 +10,11 @@ const { EXIT_CODES } = require('../../lib/enums/exitCodes');
|
|
|
10
10
|
|
|
11
11
|
const i18nKey = 'lib.prompts.selectPublicAppPrompt';
|
|
12
12
|
|
|
13
|
-
const fetchPublicAppOptions = async (
|
|
13
|
+
const fetchPublicAppOptions = async (
|
|
14
|
+
accountId,
|
|
15
|
+
accountName,
|
|
16
|
+
isMigratingApp = false
|
|
17
|
+
) => {
|
|
14
18
|
try {
|
|
15
19
|
const publicApps = await fetchPublicAppsForPortal(accountId);
|
|
16
20
|
const filteredPublicApps = publicApps.filter(
|
|
@@ -19,13 +23,15 @@ const fetchPublicAppOptions = async (accountId, accountName, migrateApp) => {
|
|
|
19
23
|
|
|
20
24
|
if (
|
|
21
25
|
!filteredPublicApps.length ||
|
|
22
|
-
(
|
|
23
|
-
!filteredPublicApps.
|
|
26
|
+
(isMigratingApp &&
|
|
27
|
+
!filteredPublicApps.some(
|
|
28
|
+
app => !app.preventProjectMigrations || !app.listingInfo
|
|
29
|
+
))
|
|
24
30
|
) {
|
|
25
|
-
const headerTranslationKey =
|
|
31
|
+
const headerTranslationKey = isMigratingApp
|
|
26
32
|
? 'noAppsMigration'
|
|
27
33
|
: 'noAppsClone';
|
|
28
|
-
const messageTranslationKey =
|
|
34
|
+
const messageTranslationKey = isMigratingApp
|
|
29
35
|
? 'noAppsMigrationMessage'
|
|
30
36
|
: 'noAppsCloneMessage';
|
|
31
37
|
uiLine();
|
|
@@ -47,14 +53,16 @@ const fetchPublicAppOptions = async (accountId, accountName, migrateApp) => {
|
|
|
47
53
|
const selectPublicAppPrompt = async ({
|
|
48
54
|
accountId,
|
|
49
55
|
accountName,
|
|
50
|
-
|
|
56
|
+
isMigratingApp = false,
|
|
51
57
|
}) => {
|
|
52
58
|
const publicApps = await fetchPublicAppOptions(
|
|
53
59
|
accountId,
|
|
54
60
|
accountName,
|
|
55
|
-
|
|
61
|
+
isMigratingApp
|
|
56
62
|
);
|
|
57
|
-
const translationKey =
|
|
63
|
+
const translationKey = isMigratingApp
|
|
64
|
+
? 'selectAppIdMigrate'
|
|
65
|
+
: 'selectAppIdClone';
|
|
58
66
|
|
|
59
67
|
return promptUser([
|
|
60
68
|
{
|
|
@@ -64,7 +72,8 @@ const selectPublicAppPrompt = async ({
|
|
|
64
72
|
}),
|
|
65
73
|
type: 'list',
|
|
66
74
|
choices: publicApps.map(app => {
|
|
67
|
-
|
|
75
|
+
const { preventProjectMigrations, listingInfo } = app;
|
|
76
|
+
if (isMigratingApp && preventProjectMigrations && listingInfo) {
|
|
68
77
|
return {
|
|
69
78
|
name: `${app.name} (${app.id})`,
|
|
70
79
|
disabled: i18n(`${i18nKey}.errors.cannotBeMigrated`),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "5.2.1-beta.
|
|
3
|
+
"version": "5.2.1-beta.13",
|
|
4
4
|
"description": "CLI for working with HubSpot",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"publishConfig": {
|
|
47
47
|
"access": "public"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "093562cbfdee6d18a528a6e330e485ad018b292f"
|
|
50
50
|
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const { promptUser } = require('./promptUtils');
|
|
4
|
-
const { i18n } = require('../lang');
|
|
5
|
-
const { getCwd, isValidPath } = require('@hubspot/local-dev-lib/path');
|
|
6
|
-
|
|
7
|
-
const i18nKey = 'lib.prompts.cloneAppLocationPrompt';
|
|
8
|
-
|
|
9
|
-
const cloneAppLocationPrompt = (promptOptions, appName) => {
|
|
10
|
-
return promptUser({
|
|
11
|
-
name: 'location',
|
|
12
|
-
message: i18n(`${i18nKey}.enterLocation`),
|
|
13
|
-
when: !promptOptions.location,
|
|
14
|
-
default: path.resolve(getCwd(), appName),
|
|
15
|
-
validate: input => {
|
|
16
|
-
if (!input) {
|
|
17
|
-
return i18n(`${i18nKey}.errors.locationRequired`);
|
|
18
|
-
}
|
|
19
|
-
if (fs.existsSync(input)) {
|
|
20
|
-
return i18n(`${i18nKey}.errors.invalidLocation`);
|
|
21
|
-
}
|
|
22
|
-
if (!isValidPath(input)) {
|
|
23
|
-
return i18n(`${i18nKey}.errors.invalidCharacters`);
|
|
24
|
-
}
|
|
25
|
-
return true;
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
module.exports = {
|
|
31
|
-
cloneAppLocationPrompt,
|
|
32
|
-
};
|