@hubspot/cli 6.0.0 → 6.1.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/commands/project/cloneApp.js +2 -1
- package/commands/project/dev.js +3 -19
- package/commands/project/migrateApp.js +13 -4
- package/lang/en.lyaml +7 -3
- package/lib/__tests__/dependencyManagement.test.js +17 -19
- package/lib/dependencyManagement.js +2 -2
- package/lib/localDev.js +25 -6
- package/package.json +2 -2
|
@@ -20,6 +20,7 @@ const {
|
|
|
20
20
|
} = require('../../lib/prompts/createProjectPrompt');
|
|
21
21
|
const { poll } = require('../../lib/polling');
|
|
22
22
|
const {
|
|
23
|
+
uiBetaTag,
|
|
23
24
|
uiLine,
|
|
24
25
|
uiCommandReference,
|
|
25
26
|
uiAccountDescription,
|
|
@@ -46,7 +47,7 @@ const { extractZipArchive } = require('@hubspot/local-dev-lib/archive');
|
|
|
46
47
|
const i18nKey = 'commands.project.subcommands.cloneApp';
|
|
47
48
|
|
|
48
49
|
exports.command = 'clone-app';
|
|
49
|
-
exports.describe =
|
|
50
|
+
exports.describe = uiBetaTag(i18n(`${i18nKey}.describe`), false);
|
|
50
51
|
|
|
51
52
|
exports.handler = async options => {
|
|
52
53
|
await loadAndValidateOptions(options);
|
package/commands/project/dev.js
CHANGED
|
@@ -21,12 +21,7 @@ const {
|
|
|
21
21
|
validateProjectConfig,
|
|
22
22
|
} = require('../../lib/projects');
|
|
23
23
|
const { EXIT_CODES } = require('../../lib/enums/exitCodes');
|
|
24
|
-
const {
|
|
25
|
-
uiAccountDescription,
|
|
26
|
-
uiBetaTag,
|
|
27
|
-
uiCommandReference,
|
|
28
|
-
uiLink,
|
|
29
|
-
} = require('../../lib/ui');
|
|
24
|
+
const { uiBetaTag, uiCommandReference, uiLink } = require('../../lib/ui');
|
|
30
25
|
const SpinniesManager = require('../../lib/ui/SpinniesManager');
|
|
31
26
|
const LocalDevManager = require('../../lib/LocalDevManager');
|
|
32
27
|
const {
|
|
@@ -52,6 +47,7 @@ const {
|
|
|
52
47
|
createInitialBuildForNewProject,
|
|
53
48
|
useExistingDevTestAccount,
|
|
54
49
|
validateAccountOption,
|
|
50
|
+
checkIfParentAccountIsAuthed,
|
|
55
51
|
} = require('../../lib/localDev');
|
|
56
52
|
|
|
57
53
|
const i18nKey = 'commands.project.subcommands.dev';
|
|
@@ -130,19 +126,7 @@ exports.handler = async options => {
|
|
|
130
126
|
await confirmDefaultAccountIsTarget(accountConfig, hasPublicApps);
|
|
131
127
|
|
|
132
128
|
if (hasPublicApps) {
|
|
133
|
-
|
|
134
|
-
if (!getAccountConfig(accountConfig.parentAccountId)) {
|
|
135
|
-
logger.error(
|
|
136
|
-
i18n(`${i18nKey}.errors.parentAccountNotConfigured`, {
|
|
137
|
-
accountId: accountConfig.parentAccountId,
|
|
138
|
-
accountIdentifier: uiAccountDescription(targetTestingAccountId),
|
|
139
|
-
authCommand: uiCommandReference(
|
|
140
|
-
`hs auth --account=${accountConfig.parentAccountId}`
|
|
141
|
-
),
|
|
142
|
-
})
|
|
143
|
-
);
|
|
144
|
-
process.exit(EXIT_CODES.ERROR);
|
|
145
|
-
}
|
|
129
|
+
checkIfParentAccountIsAuthed(accountConfig);
|
|
146
130
|
targetProjectAccountId = accountConfig.parentAccountId;
|
|
147
131
|
} else {
|
|
148
132
|
targetProjectAccountId = accountId;
|
|
@@ -52,7 +52,7 @@ const {
|
|
|
52
52
|
const i18nKey = 'commands.project.subcommands.migrateApp';
|
|
53
53
|
|
|
54
54
|
exports.command = 'migrate-app';
|
|
55
|
-
exports.describe =
|
|
55
|
+
exports.describe = uiBetaTag(i18n(`${i18nKey}.describe`), false);
|
|
56
56
|
|
|
57
57
|
exports.handler = async options => {
|
|
58
58
|
await loadAndValidateOptions(options);
|
|
@@ -63,6 +63,16 @@ exports.handler = async options => {
|
|
|
63
63
|
|
|
64
64
|
trackCommandUsage('migrate-app', {}, accountId);
|
|
65
65
|
|
|
66
|
+
logger.log('');
|
|
67
|
+
logger.log(uiBetaTag(i18n(`${i18nKey}.header.text`), false));
|
|
68
|
+
logger.log(
|
|
69
|
+
uiLink(
|
|
70
|
+
i18n(`${i18nKey}.header.link`),
|
|
71
|
+
'https://developers.hubspot.com/docs/platform/migrate-a-public-app-to-projects'
|
|
72
|
+
)
|
|
73
|
+
);
|
|
74
|
+
logger.log('');
|
|
75
|
+
|
|
66
76
|
if (!isAppDeveloperAccount(accountConfig)) {
|
|
67
77
|
uiLine();
|
|
68
78
|
logger.error(i18n(`${i18nKey}.errors.invalidAccountTypeTitle`));
|
|
@@ -85,7 +95,6 @@ exports.handler = async options => {
|
|
|
85
95
|
isMigratingApp: true,
|
|
86
96
|
});
|
|
87
97
|
|
|
88
|
-
let appName;
|
|
89
98
|
try {
|
|
90
99
|
const selectedApp = await fetchPublicAppMetadata(appId, accountId);
|
|
91
100
|
// preventProjectMigrations returns true if we have not added app to allowlist config.
|
|
@@ -96,7 +105,6 @@ exports.handler = async options => {
|
|
|
96
105
|
logger.error(i18n(`${i18nKey}.errors.invalidApp`, { appId }));
|
|
97
106
|
process.exit(EXIT_CODES.ERROR);
|
|
98
107
|
}
|
|
99
|
-
appName = selectedApp.name;
|
|
100
108
|
} catch (error) {
|
|
101
109
|
logApiErrorInstance(error, new ApiErrorContext({ accountId }));
|
|
102
110
|
process.exit(EXIT_CODES.ERROR);
|
|
@@ -134,7 +142,8 @@ exports.handler = async options => {
|
|
|
134
142
|
|
|
135
143
|
logger.log('');
|
|
136
144
|
uiLine();
|
|
137
|
-
logger.
|
|
145
|
+
logger.warn(i18n(`${i18nKey}.warning.title`));
|
|
146
|
+
logger.log('');
|
|
138
147
|
logger.log(i18n(`${i18nKey}.warning.projectConversion`));
|
|
139
148
|
logger.log(i18n(`${i18nKey}.warning.appConfig`));
|
|
140
149
|
logger.log('');
|
package/lang/en.lyaml
CHANGED
|
@@ -484,7 +484,6 @@ en:
|
|
|
484
484
|
noProjectConfig: "No project detected. Please run this command again from a project directory."
|
|
485
485
|
invalidProjectComponents: "Projects cannot contain both private and public apps. Move your apps to separate projects before attempting local development."
|
|
486
486
|
noRunnableComponents: "No supported components were found in this project. Run {{ command }} to see a list of available components and add one to your project."
|
|
487
|
-
parentAccountNotConfigured: "To develop this project locally, run {{ authCommand }} to authenticate the App Developer Account {{ accountId }} associated with {{ accountIdentifier }}."
|
|
488
487
|
examples:
|
|
489
488
|
default: "Start local dev for the current project"
|
|
490
489
|
create:
|
|
@@ -513,13 +512,16 @@ en:
|
|
|
513
512
|
describe: "Directory where project should be created"
|
|
514
513
|
name:
|
|
515
514
|
describe: "Project name (cannot be changed)"
|
|
515
|
+
header:
|
|
516
|
+
text: "Migrate an app to the projects framework"
|
|
517
|
+
link: "Learn more about migrating apps to the projects framework"
|
|
516
518
|
migrationStatus:
|
|
517
519
|
inProgress: "Converting app configuration to {{#bold}}public-app.json{{/bold}} component definition ..."
|
|
518
520
|
success: "{{#bold}}Your app was converted and build #1 is deployed{{/bold}}"
|
|
519
521
|
done: "Converting app configuration to public-app.json component definition ... DONE"
|
|
520
522
|
failure: "Converting app configuration to public-app.json component definition ... FAILED"
|
|
521
523
|
warning:
|
|
522
|
-
title: "{{#bold}}
|
|
524
|
+
title: "{{#bold}}You are about to migrate an app to the projects framework{{/bold}}"
|
|
523
525
|
projectConversion: "{{#bold}}The selected app will be converted to a project component.{{/bold}}"
|
|
524
526
|
appConfig: "All supported app configuration will be moved to the {{#bold}}public-app.json{{/bold}} component definition file. Future updates to those features must be made through the project build and deploy pipeline, not the developer account UI."
|
|
525
527
|
buildAndDeploy: "This will create a new project with a single app component and immediately build and deploy it to your developer account (build #1)."
|
|
@@ -1023,6 +1025,8 @@ en:
|
|
|
1023
1025
|
createInitialBuildForNewProject:
|
|
1024
1026
|
initialUploadMessage: "HubSpot Local Dev Server Startup"
|
|
1025
1027
|
projectLockedError: "Your project is locked. This may mean that another user is running the {{#bold}}`hs project watch`{{/bold}} command for this project. If this is you, unlock the project in Projects UI."
|
|
1028
|
+
checkIfParentAccountIsAuthed:
|
|
1029
|
+
notAuthedError: "To develop this project locally, run {{ authCommand }} to authenticate the App Developer Account {{ accountId }} associated with {{ accountIdentifier }}."
|
|
1026
1030
|
projects:
|
|
1027
1031
|
config:
|
|
1028
1032
|
srcOutsideProjectDir: "Invalid value for 'srcDir' in {{ projectConfig }}: {{#bold}}srcDir: \"{{ srcDir }}\"{{/bold}}\n\t'srcDir' must be a relative path to a folder under the project root, such as \".\" or \"./src\""
|
|
@@ -1218,7 +1222,7 @@ en:
|
|
|
1218
1222
|
languageRequired: "Please select API sample app's language"
|
|
1219
1223
|
createProjectPrompt:
|
|
1220
1224
|
enterName: "[--name] Give your project a name: "
|
|
1221
|
-
enterLocation: "[--location]
|
|
1225
|
+
enterLocation: "[--location] Enter the folder to create the project in:"
|
|
1222
1226
|
selectTemplate: "[--template] Choose a project template: "
|
|
1223
1227
|
errors:
|
|
1224
1228
|
nameRequired: "A project name is required"
|
|
@@ -28,6 +28,7 @@ describe('cli/lib/dependencyManagement', () => {
|
|
|
28
28
|
const appFunctionsDir = path.join(appDir, 'app.functions');
|
|
29
29
|
const extensionsDir = path.join(appDir, 'exensions');
|
|
30
30
|
const projectName = 'super cool test project';
|
|
31
|
+
const installLocations = [appFunctionsDir, extensionsDir];
|
|
31
32
|
|
|
32
33
|
beforeEach(() => {
|
|
33
34
|
execMock = jest.fn();
|
|
@@ -64,7 +65,6 @@ describe('cli/lib/dependencyManagement', () => {
|
|
|
64
65
|
describe('installPackages', () => {
|
|
65
66
|
it('should setup a loading spinner', async () => {
|
|
66
67
|
const packages = ['package1', 'package2'];
|
|
67
|
-
const installLocations = ['src/app/app.functions', 'src/app/extensions'];
|
|
68
68
|
await installPackages({ packages, installLocations });
|
|
69
69
|
expect(SpinniesManager.init).toHaveBeenCalledTimes(
|
|
70
70
|
installLocations.length
|
|
@@ -79,7 +79,6 @@ describe('cli/lib/dependencyManagement', () => {
|
|
|
79
79
|
|
|
80
80
|
it('should install the provided packages in all the provided install locations', async () => {
|
|
81
81
|
const packages = ['package1', 'package2'];
|
|
82
|
-
const installLocations = ['src/app/app.functions', 'src/app/extensions'];
|
|
83
82
|
await installPackages({ packages, installLocations });
|
|
84
83
|
|
|
85
84
|
expect(execMock).toHaveBeenCalledTimes(installLocations.length);
|
|
@@ -91,9 +90,9 @@ describe('cli/lib/dependencyManagement', () => {
|
|
|
91
90
|
);
|
|
92
91
|
|
|
93
92
|
for (const location of installLocations) {
|
|
94
|
-
expect(execMock).toHaveBeenCalledWith(
|
|
95
|
-
|
|
96
|
-
);
|
|
93
|
+
expect(execMock).toHaveBeenCalledWith(`npm install package1 package2`, {
|
|
94
|
+
cwd: location,
|
|
95
|
+
});
|
|
97
96
|
expect(SpinniesManager.add).toHaveBeenCalledWith(
|
|
98
97
|
`installingDependencies-${location}`,
|
|
99
98
|
{
|
|
@@ -110,15 +109,14 @@ describe('cli/lib/dependencyManagement', () => {
|
|
|
110
109
|
});
|
|
111
110
|
|
|
112
111
|
it('should use the provided install locations', async () => {
|
|
113
|
-
const installLocations = ['src/app/app.functions', 'src/app/extensions'];
|
|
114
112
|
await installPackages({ installLocations });
|
|
115
113
|
expect(execMock).toHaveBeenCalledTimes(installLocations.length);
|
|
116
|
-
expect(execMock).toHaveBeenCalledWith(
|
|
117
|
-
|
|
118
|
-
);
|
|
119
|
-
expect(execMock).toHaveBeenCalledWith(
|
|
120
|
-
|
|
121
|
-
);
|
|
114
|
+
expect(execMock).toHaveBeenCalledWith(`npm install`, {
|
|
115
|
+
cwd: appFunctionsDir,
|
|
116
|
+
});
|
|
117
|
+
expect(execMock).toHaveBeenCalledWith(`npm install`, {
|
|
118
|
+
cwd: extensionsDir,
|
|
119
|
+
});
|
|
122
120
|
});
|
|
123
121
|
|
|
124
122
|
it('should locate the projects package.json files when install locations is not provided', async () => {
|
|
@@ -137,14 +135,14 @@ describe('cli/lib/dependencyManagement', () => {
|
|
|
137
135
|
});
|
|
138
136
|
|
|
139
137
|
await installPackages({});
|
|
140
|
-
//
|
|
138
|
+
// It's called once per each install location, plus once to check if npm installed
|
|
141
139
|
expect(execMock).toHaveBeenCalledTimes(installLocations.length + 1);
|
|
142
|
-
expect(execMock).toHaveBeenCalledWith(
|
|
143
|
-
|
|
144
|
-
);
|
|
145
|
-
expect(execMock).toHaveBeenCalledWith(
|
|
146
|
-
|
|
147
|
-
);
|
|
140
|
+
expect(execMock).toHaveBeenCalledWith(`npm install`, {
|
|
141
|
+
cwd: appFunctionsDir,
|
|
142
|
+
});
|
|
143
|
+
expect(execMock).toHaveBeenCalledWith(`npm install`, {
|
|
144
|
+
cwd: extensionsDir,
|
|
145
|
+
});
|
|
148
146
|
});
|
|
149
147
|
|
|
150
148
|
it('should throw an error when installing the dependencies fails', async () => {
|
|
@@ -62,7 +62,7 @@ async function installPackagesInDirectory(packages, directory) {
|
|
|
62
62
|
directory: relativeDir,
|
|
63
63
|
}),
|
|
64
64
|
});
|
|
65
|
-
let installCommand = `${DEFAULT_PACKAGE_MANAGER}
|
|
65
|
+
let installCommand = `${DEFAULT_PACKAGE_MANAGER} install`;
|
|
66
66
|
|
|
67
67
|
if (packages) {
|
|
68
68
|
installCommand = `${installCommand} ${packages.join(' ')}`;
|
|
@@ -71,7 +71,7 @@ async function installPackagesInDirectory(packages, directory) {
|
|
|
71
71
|
logger.debug(`Running ${installCommand}`);
|
|
72
72
|
try {
|
|
73
73
|
const exec = util.promisify(execAsync);
|
|
74
|
-
await exec(installCommand);
|
|
74
|
+
await exec(installCommand, { cwd: directory });
|
|
75
75
|
SpinniesManager.succeed(spinner, {
|
|
76
76
|
text: i18n(`${i18nKey}.installationSuccessful`, {
|
|
77
77
|
directory: relativeDir,
|
package/lib/localDev.js
CHANGED
|
@@ -95,16 +95,34 @@ const checkIfAppDeveloperAccount = accountConfig => {
|
|
|
95
95
|
}
|
|
96
96
|
};
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (hasPublicApps && !isDeveloperTestAccount(accountConfig)) {
|
|
98
|
+
const checkIfParentAccountIsAuthed = accountConfig => {
|
|
99
|
+
if (!getAccountConfig(accountConfig.parentAccountId)) {
|
|
101
100
|
logger.error(
|
|
102
|
-
i18n(`${i18nKey}.
|
|
103
|
-
|
|
104
|
-
|
|
101
|
+
i18n(`${i18nKey}.checkIfParentAccountIsAuthed.notAuthedError`, {
|
|
102
|
+
accountId: accountConfig.parentAccountId,
|
|
103
|
+
accountIdentifier: uiAccountDescription(accountConfig.portalId),
|
|
104
|
+
authCommand: uiCommandReference(
|
|
105
|
+
`hs auth --account=${accountConfig.parentAccountId}`
|
|
106
|
+
),
|
|
105
107
|
})
|
|
106
108
|
);
|
|
107
109
|
process.exit(EXIT_CODES.SUCCESS);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// Confirm the default account is a developer account if developing public apps
|
|
114
|
+
const validateAccountOption = (accountConfig, hasPublicApps) => {
|
|
115
|
+
if (hasPublicApps) {
|
|
116
|
+
if (!isDeveloperTestAccount) {
|
|
117
|
+
logger.error(
|
|
118
|
+
i18n(`${i18nKey}.validateAccountOption.invalidPublicAppAccount`, {
|
|
119
|
+
useCommand: uiCommandReference('hs accounts use'),
|
|
120
|
+
devCommand: uiCommandReference('hs project dev'),
|
|
121
|
+
})
|
|
122
|
+
);
|
|
123
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
124
|
+
}
|
|
125
|
+
checkIfParentAccountIsAuthed(accountConfig);
|
|
108
126
|
} else if (isAppDeveloperAccount(accountConfig)) {
|
|
109
127
|
logger.error(
|
|
110
128
|
i18n(`${i18nKey}.validateAccountOption.invalidPrivateAppAccount`, {
|
|
@@ -456,4 +474,5 @@ module.exports = {
|
|
|
456
474
|
createNewProjectForLocalDev,
|
|
457
475
|
createInitialBuildForNewProject,
|
|
458
476
|
getAccountHomeUrl,
|
|
477
|
+
checkIfParentAccountIsAuthed,
|
|
459
478
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.1.0",
|
|
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": "51f7638e491a999b6f64a9f3bda3c4d05fff0dbc"
|
|
50
50
|
}
|