@hubspot/cli 7.9.0-beta.1 → 7.9.0-experimental.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commands/__tests__/project.test.js +2 -0
- package/commands/account/createOverride.js +2 -12
- package/commands/account/removeOverride.js +2 -10
- package/commands/cms/theme/preview.js +1 -4
- package/commands/getStarted.js +7 -19
- package/commands/project/__tests__/deploy.test.js +4 -3
- package/commands/project/__tests__/updateDeps.test.d.ts +1 -0
- package/commands/project/__tests__/updateDeps.test.js +142 -0
- package/commands/project/create.js +0 -1
- package/commands/project/updateDeps.d.ts +6 -0
- package/commands/project/updateDeps.js +80 -0
- package/commands/project.js +2 -0
- package/commands/testAccount/create.js +1 -1
- package/lang/en.d.ts +30 -15
- package/lang/en.js +32 -18
- package/lib/__tests__/dependencyManagement.test.js +273 -1
- package/lib/__tests__/npm.test.js +1 -1
- package/lib/__tests__/sandboxSync.test.js +1 -1
- package/lib/__tests__/usageTracking.test.js +2 -2
- package/lib/commonOpts.js +2 -5
- package/lib/configMigrate.js +3 -3
- package/lib/dependencyManagement.d.ts +8 -2
- package/lib/dependencyManagement.js +75 -12
- package/lib/doctor/DiagnosticInfoBuilder.js +1 -1
- package/lib/doctor/Doctor.js +1 -1
- package/lib/doctor/__tests__/DiagnosticInfoBuilder.test.js +4 -2
- package/lib/doctor/__tests__/Doctor.test.js +1 -1
- package/lib/jsonLoader.d.ts +14 -0
- package/lib/jsonLoader.js +60 -0
- package/lib/middleware/__test__/requestMiddleware.test.js +1 -1
- package/lib/middleware/autoUpdateMiddleware.js +1 -1
- package/lib/middleware/commandTargetingUtils.js +1 -0
- package/lib/middleware/fireAlarmMiddleware.js +1 -1
- package/lib/middleware/notificationsMiddleware.js +1 -1
- package/lib/middleware/requestMiddleware.js +1 -1
- package/lib/npm.d.ts +3 -0
- package/lib/npm.js +7 -1
- package/lib/projects/__tests__/AppDevModeInterface.test.js +3 -0
- package/lib/projects/__tests__/platformVersion.test.js +5 -1
- package/lib/projects/create/__tests__/v2.test.js +20 -14
- package/lib/projects/create/v2.js +8 -13
- package/lib/projects/localDev/LocalDevLogger.js +2 -2
- package/lib/projects/localDev/LocalDevManager_DEPRECATED.js +3 -3
- package/lib/projects/localDev/LocalDevWebsocketServer.js +1 -1
- package/lib/projects/platformVersion.js +1 -1
- package/lib/prompts/promptUtils.d.ts +8 -0
- package/lib/prompts/promptUtils.js +7 -1
- package/lib/prompts/selectProjectTemplatePrompt.js +4 -0
- package/lib/sandboxSync.js +1 -1
- package/lib/usageTracking.js +2 -2
- package/mcp-server/tools/cms/HsCreateFunctionTool.js +2 -2
- package/mcp-server/tools/cms/HsCreateModuleTool.js +2 -2
- package/mcp-server/tools/cms/HsCreateTemplateTool.js +2 -2
- package/mcp-server/tools/cms/HsFunctionLogsTool.js +2 -9
- package/mcp-server/tools/cms/HsListFunctionsTool.js +1 -1
- package/mcp-server/tools/cms/HsListTool.js +1 -1
- package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +7 -4
- package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.js +7 -3
- package/mcp-server/tools/cms/__tests__/HsCreateTemplateTool.test.js +7 -4
- package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.js +5 -1
- package/mcp-server/tools/cms/__tests__/HsListFunctionsTool.test.js +8 -3
- package/mcp-server/tools/cms/__tests__/HsListTool.test.js +8 -3
- package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +4 -1
- package/mcp-server/tools/project/AddFeatureToProjectTool.js +6 -5
- package/mcp-server/tools/project/CreateProjectTool.js +2 -2
- package/mcp-server/tools/project/DeployProjectTool.d.ts +4 -1
- package/mcp-server/tools/project/DeployProjectTool.js +4 -3
- package/mcp-server/tools/project/DocFetchTool.d.ts +4 -1
- package/mcp-server/tools/project/DocFetchTool.js +7 -6
- package/mcp-server/tools/project/DocsSearchTool.js +5 -5
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.d.ts +4 -1
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +7 -5
- package/mcp-server/tools/project/GetApplicationInfoTool.d.ts +8 -2
- package/mcp-server/tools/project/GetApplicationInfoTool.js +7 -6
- package/mcp-server/tools/project/GetConfigValuesTool.js +4 -4
- package/mcp-server/tools/project/GuidedWalkthroughTool.d.ts +4 -1
- package/mcp-server/tools/project/GuidedWalkthroughTool.js +6 -14
- package/mcp-server/tools/project/UploadProjectTools.d.ts +4 -1
- package/mcp-server/tools/project/UploadProjectTools.js +4 -3
- package/mcp-server/tools/project/ValidateProjectTool.d.ts +4 -1
- package/mcp-server/tools/project/ValidateProjectTool.js +5 -4
- package/mcp-server/tools/project/__tests__/AddFeatureToProjectTool.test.js +6 -1
- package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +7 -3
- package/mcp-server/tools/project/__tests__/DeployProjectTool.test.js +7 -2
- package/mcp-server/tools/project/__tests__/DocFetchTool.test.js +8 -3
- package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +6 -2
- package/mcp-server/tools/project/__tests__/GetApiUsagePatternsByAppIdTool.test.js +8 -3
- package/mcp-server/tools/project/__tests__/GetApplicationInfoTool.test.js +9 -5
- package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +6 -2
- package/mcp-server/tools/project/__tests__/GuidedWalkthroughTool.test.js +43 -13
- package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +8 -2
- package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +8 -2
- package/mcp-server/utils/__tests__/content.test.d.ts +1 -0
- package/mcp-server/utils/__tests__/content.test.js +166 -0
- package/mcp-server/utils/__tests__/feedbackTracking.test.d.ts +1 -0
- package/mcp-server/utils/__tests__/feedbackTracking.test.js +121 -0
- package/mcp-server/utils/content.d.ts +1 -1
- package/mcp-server/utils/content.js +8 -1
- package/mcp-server/utils/feedbackTracking.d.ts +1 -0
- package/mcp-server/utils/feedbackTracking.js +41 -0
- package/package.json +2 -2
- package/commands/project/__tests__/fixtures/exampleProject.json +0 -33
- package/lang/en.lyaml +0 -1508
- package/lib/lang.d.ts +0 -8
- package/lib/lang.js +0 -72
|
@@ -13,6 +13,7 @@ import migrateApp from '../project/migrateApp.js';
|
|
|
13
13
|
import migrate from '../project/migrate.js';
|
|
14
14
|
import cloneApp from '../project/cloneApp.js';
|
|
15
15
|
import installDeps from '../project/installDeps.js';
|
|
16
|
+
import updateDeps from '../project/updateDeps.js';
|
|
16
17
|
import validate from '../project/validate.js';
|
|
17
18
|
import profileCommands from '../project/profile.js';
|
|
18
19
|
import list from '../project/list.js';
|
|
@@ -72,6 +73,7 @@ describe('commands/project', () => {
|
|
|
72
73
|
migrate,
|
|
73
74
|
cloneApp,
|
|
74
75
|
installDeps,
|
|
76
|
+
updateDeps,
|
|
75
77
|
profileCommands,
|
|
76
78
|
validate,
|
|
77
79
|
list,
|
|
@@ -6,7 +6,7 @@ import { getCWDAccountOverride, getDefaultAccountOverrideFilePath, getConfigPath
|
|
|
6
6
|
import { getGlobalConfig } from '@hubspot/local-dev-lib/config/migrate';
|
|
7
7
|
import { promptUser } from '../../lib/prompts/promptUtils.js';
|
|
8
8
|
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
9
|
-
import {
|
|
9
|
+
import { trackCommandUsage } from '../../lib/usageTracking.js';
|
|
10
10
|
import { selectAccountFromConfig } from '../../lib/prompts/accountsPrompt.js';
|
|
11
11
|
import { logError } from '../../lib/errorHandlers/index.js';
|
|
12
12
|
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
@@ -32,11 +32,6 @@ async function handler(args) {
|
|
|
32
32
|
});
|
|
33
33
|
uiLogger.log('');
|
|
34
34
|
if (!replaceOverrideFile) {
|
|
35
|
-
const accountId = getAccountId(accountOverride) || undefined;
|
|
36
|
-
trackCommandMetadataUsage('account-createOverride', {
|
|
37
|
-
command: 'hs account create-override',
|
|
38
|
-
step: 'Reject overwriting an override via prompt',
|
|
39
|
-
}, accountId);
|
|
40
35
|
process.exit(EXIT_CODES.SUCCESS);
|
|
41
36
|
}
|
|
42
37
|
}
|
|
@@ -48,16 +43,11 @@ async function handler(args) {
|
|
|
48
43
|
overrideDefaultAccount = await selectAccountFromConfig();
|
|
49
44
|
}
|
|
50
45
|
const accountId = getAccountId(overrideDefaultAccount);
|
|
46
|
+
trackCommandUsage('account-createOverride', undefined, accountId);
|
|
51
47
|
try {
|
|
52
48
|
const overrideFilePath = path.join(getCwd(), DEFAULT_ACCOUNT_OVERRIDE_FILE_NAME);
|
|
53
49
|
await fs.writeFile(overrideFilePath, accountId.toString(), 'utf8');
|
|
54
50
|
uiLogger.success(commands.account.subcommands.createOverride.success(overrideFilePath));
|
|
55
|
-
const trackingId = accountId || undefined;
|
|
56
|
-
trackCommandMetadataUsage('config-migrate', {
|
|
57
|
-
command: 'hs config migrate',
|
|
58
|
-
step: 'Confirm overwriting an override via prompt',
|
|
59
|
-
successful: true,
|
|
60
|
-
}, trackingId);
|
|
61
51
|
process.exit(EXIT_CODES.SUCCESS);
|
|
62
52
|
}
|
|
63
53
|
catch (e) {
|
|
@@ -3,7 +3,7 @@ import { getCWDAccountOverride, getDefaultAccountOverrideFilePath, getAccountId,
|
|
|
3
3
|
import { DEFAULT_ACCOUNT_OVERRIDE_FILE_NAME } from '@hubspot/local-dev-lib/constants/config';
|
|
4
4
|
import { getGlobalConfig } from '@hubspot/local-dev-lib/config/migrate';
|
|
5
5
|
import { promptUser } from '../../lib/prompts/promptUtils.js';
|
|
6
|
-
import {
|
|
6
|
+
import { trackCommandUsage } from '../../lib/usageTracking.js';
|
|
7
7
|
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
8
8
|
import { logError } from '../../lib/errorHandlers/index.js';
|
|
9
9
|
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
@@ -22,6 +22,7 @@ async function handler(args) {
|
|
|
22
22
|
const overrideFilePath = getDefaultAccountOverrideFilePath();
|
|
23
23
|
if (accountOverride && overrideFilePath) {
|
|
24
24
|
const accountId = getAccountId(accountOverride) || undefined;
|
|
25
|
+
trackCommandUsage('account-removeOverride', undefined, accountId);
|
|
25
26
|
if (!force) {
|
|
26
27
|
uiLogger.log(commands.account.subcommands.removeOverride.accountOverride(overrideFilePath, accountOverride.toString()));
|
|
27
28
|
const { deleteOverrideFile } = await promptUser({
|
|
@@ -32,21 +33,12 @@ async function handler(args) {
|
|
|
32
33
|
});
|
|
33
34
|
uiLogger.log('');
|
|
34
35
|
if (!deleteOverrideFile) {
|
|
35
|
-
trackCommandMetadataUsage('account-removeOverride', {
|
|
36
|
-
command: 'hs account remove-override',
|
|
37
|
-
step: 'Reject removing override via prompt',
|
|
38
|
-
}, accountId);
|
|
39
36
|
process.exit(EXIT_CODES.SUCCESS);
|
|
40
37
|
}
|
|
41
38
|
}
|
|
42
39
|
try {
|
|
43
40
|
fs.unlinkSync(overrideFilePath);
|
|
44
41
|
uiLogger.success(commands.account.subcommands.removeOverride.success);
|
|
45
|
-
trackCommandMetadataUsage('account-removeOverride', {
|
|
46
|
-
command: 'hs account remove-override',
|
|
47
|
-
step: 'Confirm removing override file (via prompt/force)',
|
|
48
|
-
successful: true,
|
|
49
|
-
}, accountId);
|
|
50
42
|
process.exit(EXIT_CODES.SUCCESS);
|
|
51
43
|
}
|
|
52
44
|
catch (error) {
|
|
@@ -142,14 +142,11 @@ async function handler(args) {
|
|
|
142
142
|
trackCommandUsage('preview', {}, derivedAccountId);
|
|
143
143
|
let createUnifiedDevServer;
|
|
144
144
|
try {
|
|
145
|
-
// @ts-ignore TODO: Remove when we deprecate Node 18
|
|
146
|
-
require.resolve('@hubspot/cms-dev-server');
|
|
147
|
-
// @ts-ignore TODO: Remove when we deprecate Node 18
|
|
148
145
|
const { createDevServer } = await import('@hubspot/cms-dev-server');
|
|
149
146
|
createUnifiedDevServer = createDevServer;
|
|
150
147
|
}
|
|
151
148
|
catch (e) {
|
|
152
|
-
uiLogger.warn('
|
|
149
|
+
uiLogger.warn('Error loading unified dev server. Defaulting to legacy preview.');
|
|
153
150
|
}
|
|
154
151
|
if (createUnifiedDevServer) {
|
|
155
152
|
if (port) {
|
package/commands/getStarted.js
CHANGED
|
@@ -11,11 +11,10 @@ import { promptUser } from '../lib/prompts/promptUtils.js';
|
|
|
11
11
|
import { projectNameAndDestPrompt } from '../lib/prompts/projectNameAndDestPrompt.js';
|
|
12
12
|
import { uiAccountDescription, uiFeatureHighlight, uiInfoSection, } from '../lib/ui/index.js';
|
|
13
13
|
import { uiLogger } from '../lib/ui/logger.js';
|
|
14
|
-
import { debugError
|
|
14
|
+
import { debugError } from '../lib/errorHandlers/index.js';
|
|
15
15
|
import { handleProjectUpload } from '../lib/projects/upload.js';
|
|
16
16
|
import { PROJECT_CONFIG_FILE, GET_STARTED_OPTIONS, HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, } from '../lib/constants.js';
|
|
17
17
|
import { writeProjectConfig, getProjectConfig, validateProjectConfig, } from '../lib/projects/config.js';
|
|
18
|
-
import { getProjectPackageJsonLocations, installPackages, } from '../lib/dependencyManagement.js';
|
|
19
18
|
import { pollProjectBuildAndDeploy } from '../lib/projects/pollProjectBuildAndDeploy.js';
|
|
20
19
|
import { isV2Project } from '../lib/projects/platformVersion.js';
|
|
21
20
|
import { openLink } from '../lib/links.js';
|
|
@@ -135,23 +134,7 @@ async function handler(args) {
|
|
|
135
134
|
successful: true,
|
|
136
135
|
step: 'project-creation',
|
|
137
136
|
}, derivedAccountId);
|
|
138
|
-
// 5.
|
|
139
|
-
const installLocations = await getProjectPackageJsonLocations(projectDest);
|
|
140
|
-
try {
|
|
141
|
-
await installPackages({
|
|
142
|
-
installLocations: installLocations,
|
|
143
|
-
});
|
|
144
|
-
uiLogger.log(' ');
|
|
145
|
-
uiLogger.success(commands.getStarted.logs.dependenciesInstalled);
|
|
146
|
-
uiLogger.log(' ');
|
|
147
|
-
}
|
|
148
|
-
catch (err) {
|
|
149
|
-
uiLogger.log(' ');
|
|
150
|
-
uiLogger.error(commands.getStarted.errors.installDepsFailed);
|
|
151
|
-
logError(err);
|
|
152
|
-
uiLogger.log(' ');
|
|
153
|
-
}
|
|
154
|
-
// 6. Ask user if they want to upload the project
|
|
137
|
+
// 5. Ask user if they want to upload the project
|
|
155
138
|
const { shouldUpload } = await promptUser([
|
|
156
139
|
{
|
|
157
140
|
type: 'confirm',
|
|
@@ -256,6 +239,11 @@ async function handler(args) {
|
|
|
256
239
|
process.exit(EXIT_CODES.ERROR);
|
|
257
240
|
}
|
|
258
241
|
}
|
|
242
|
+
else {
|
|
243
|
+
uiLogger.log(' ');
|
|
244
|
+
uiFeatureHighlight(['projectUploadCommand', 'projectDevCommand']);
|
|
245
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
246
|
+
}
|
|
259
247
|
}
|
|
260
248
|
// Track successful completion of get-started command
|
|
261
249
|
await trackCommandMetadataUsage('get-started', {
|
|
@@ -12,8 +12,9 @@ import * as projectNamePrompt from '../../../lib/prompts/projectNamePrompt.js';
|
|
|
12
12
|
import * as promptUtils from '../../../lib/prompts/promptUtils.js';
|
|
13
13
|
import { trackCommandUsage } from '../../../lib/usageTracking.js';
|
|
14
14
|
import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
|
|
15
|
-
import
|
|
15
|
+
import { loadJson } from '../../../lib/jsonLoader.js';
|
|
16
16
|
import { mockHubSpotHttpResponse, mockHubSpotHttpError, } from '../../../lib/testUtils.js';
|
|
17
|
+
const exampleProject = loadJson(import.meta.url, './fixtures/exampleProject.json');
|
|
17
18
|
import projectDeployCommand from '../deploy.js';
|
|
18
19
|
import { uiLogger } from '../../../lib/ui/logger.js';
|
|
19
20
|
vi.mock('@hubspot/local-dev-lib/api/projects');
|
|
@@ -204,7 +205,7 @@ describe('commands/project/deploy', () => {
|
|
|
204
205
|
expect(processExitSpy).toHaveBeenCalledWith(EXIT_CODES.ERROR);
|
|
205
206
|
});
|
|
206
207
|
it('should log an error and exit when buildId option is not a valid build', async () => {
|
|
207
|
-
args.buildId = exampleProject.latestBuild
|
|
208
|
+
args.buildId = (exampleProject.latestBuild?.buildId ?? 0) + 1;
|
|
208
209
|
await projectDeployCommand.handler(args);
|
|
209
210
|
expect(uiLogger.error).toHaveBeenCalledTimes(1);
|
|
210
211
|
expect(uiLogger.error).toHaveBeenCalledWith(expect.stringMatching(`Build ${args.buildId} does not exist for project`));
|
|
@@ -222,7 +223,7 @@ describe('commands/project/deploy', () => {
|
|
|
222
223
|
it('should prompt for build id if no option is provided', async () => {
|
|
223
224
|
delete args.buildId;
|
|
224
225
|
promptUserSpy.mockResolvedValue({
|
|
225
|
-
buildId: exampleProject.latestBuild
|
|
226
|
+
buildId: exampleProject.latestBuild?.buildId ?? 0,
|
|
226
227
|
});
|
|
227
228
|
await projectDeployCommand.handler(args);
|
|
228
229
|
expect(promptUserSpy).toHaveBeenCalledTimes(1);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import yargs from 'yargs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { uiLogger } from '../../../lib/ui/logger.js';
|
|
4
|
+
import * as projectUtils from '../../../lib/projects/config.js';
|
|
5
|
+
import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
|
|
6
|
+
import { trackCommandUsage } from '../../../lib/usageTracking.js';
|
|
7
|
+
import * as dependencyManagement from '../../../lib/dependencyManagement.js';
|
|
8
|
+
import * as promptUtils from '../../../lib/prompts/promptUtils.js';
|
|
9
|
+
import projectUpdateDepsCommand from '../updateDeps.js';
|
|
10
|
+
vi.mock('../../../lib/ui/logger.js');
|
|
11
|
+
vi.mock('../../../lib/projects/config');
|
|
12
|
+
vi.mock('../../../lib/dependencyManagement');
|
|
13
|
+
vi.mock('../../../lib/prompts/promptUtils');
|
|
14
|
+
vi.mock('../../../lib/usageTracking');
|
|
15
|
+
vi.mock('../../../lib/commonOpts');
|
|
16
|
+
const exampleSpy = vi.spyOn(yargs, 'example');
|
|
17
|
+
const processExitSpy = vi.spyOn(process, 'exit');
|
|
18
|
+
const getProjectConfigSpy = vi.spyOn(projectUtils, 'getProjectConfig');
|
|
19
|
+
const promptUserSpy = vi.spyOn(promptUtils, 'promptUser');
|
|
20
|
+
const getProjectPackageJsonLocationsSpy = vi.spyOn(dependencyManagement, 'getProjectPackageJsonLocations');
|
|
21
|
+
const updatePackagesSpy = vi.spyOn(dependencyManagement, 'updatePackages');
|
|
22
|
+
describe('commands/project/updateDeps', () => {
|
|
23
|
+
describe('command', () => {
|
|
24
|
+
it('should have the correct command structure', () => {
|
|
25
|
+
expect(projectUpdateDepsCommand.command).toEqual('update-deps [packages..]');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
describe('describe', () => {
|
|
29
|
+
it('should not provide a description', () => {
|
|
30
|
+
expect(projectUpdateDepsCommand.describe).toEqual(expect.stringMatching(/Update the npm dependencies for your project, or update specific dependencies in a subcomponent of a project/));
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe('builder', () => {
|
|
34
|
+
it('should provide examples', () => {
|
|
35
|
+
projectUpdateDepsCommand.builder(yargs);
|
|
36
|
+
expect(exampleSpy).toHaveBeenCalledTimes(1);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe('handler', () => {
|
|
40
|
+
let args;
|
|
41
|
+
beforeEach(() => {
|
|
42
|
+
args = {
|
|
43
|
+
derivedAccountId: 999999,
|
|
44
|
+
};
|
|
45
|
+
// @ts-expect-error Doesn't match the actual signature because then the linter complains about unused variables
|
|
46
|
+
processExitSpy.mockImplementation(() => { });
|
|
47
|
+
});
|
|
48
|
+
it('should track the command usage', async () => {
|
|
49
|
+
await projectUpdateDepsCommand.handler(args);
|
|
50
|
+
expect(trackCommandUsage).toHaveBeenCalledTimes(1);
|
|
51
|
+
expect(trackCommandUsage).toHaveBeenCalledWith('project-update-deps', undefined, args.derivedAccountId);
|
|
52
|
+
});
|
|
53
|
+
it('should handle exceptions', async () => {
|
|
54
|
+
const error = new Error('Something went super wrong');
|
|
55
|
+
getProjectConfigSpy.mockImplementationOnce(() => {
|
|
56
|
+
throw error;
|
|
57
|
+
});
|
|
58
|
+
await projectUpdateDepsCommand.handler(args);
|
|
59
|
+
expect(uiLogger.error).toHaveBeenCalledTimes(1);
|
|
60
|
+
expect(uiLogger.error).toHaveBeenCalledWith(error.message);
|
|
61
|
+
expect(processExitSpy).toHaveBeenCalledTimes(1);
|
|
62
|
+
expect(processExitSpy).toHaveBeenCalledWith(EXIT_CODES.ERROR);
|
|
63
|
+
});
|
|
64
|
+
it('should log an error and exit when the project config is not defined', async () => {
|
|
65
|
+
getProjectConfigSpy.mockResolvedValueOnce({
|
|
66
|
+
projectDir: null,
|
|
67
|
+
projectConfig: null,
|
|
68
|
+
});
|
|
69
|
+
await projectUpdateDepsCommand.handler(args);
|
|
70
|
+
expect(uiLogger.error).toHaveBeenCalledTimes(1);
|
|
71
|
+
expect(uiLogger.error).toHaveBeenCalledWith('No project detected. Run this command from a project directory.');
|
|
72
|
+
expect(processExitSpy).toHaveBeenCalledTimes(1);
|
|
73
|
+
expect(processExitSpy).toHaveBeenCalledWith(EXIT_CODES.ERROR);
|
|
74
|
+
});
|
|
75
|
+
it('should log an error and exit when the project config has no projectDir', async () => {
|
|
76
|
+
getProjectConfigSpy.mockResolvedValueOnce({
|
|
77
|
+
projectDir: null,
|
|
78
|
+
projectConfig: null,
|
|
79
|
+
});
|
|
80
|
+
await projectUpdateDepsCommand.handler(args);
|
|
81
|
+
expect(uiLogger.error).toHaveBeenCalledTimes(1);
|
|
82
|
+
expect(uiLogger.error).toHaveBeenCalledWith('No project detected. Run this command from a project directory.');
|
|
83
|
+
expect(processExitSpy).toHaveBeenCalledTimes(1);
|
|
84
|
+
expect(processExitSpy).toHaveBeenCalledWith(EXIT_CODES.ERROR);
|
|
85
|
+
});
|
|
86
|
+
it('should prompt for input when packages is defined', async () => {
|
|
87
|
+
const projectDir = 'src';
|
|
88
|
+
getProjectConfigSpy.mockResolvedValue({
|
|
89
|
+
projectDir,
|
|
90
|
+
projectConfig: null,
|
|
91
|
+
});
|
|
92
|
+
const packageJsonLocation = path.join(projectDir, 'directory1');
|
|
93
|
+
promptUserSpy.mockResolvedValueOnce({
|
|
94
|
+
selectedInstallLocations: packageJsonLocation,
|
|
95
|
+
});
|
|
96
|
+
getProjectPackageJsonLocationsSpy.mockResolvedValue([
|
|
97
|
+
packageJsonLocation,
|
|
98
|
+
]);
|
|
99
|
+
await projectUpdateDepsCommand.handler({
|
|
100
|
+
...args,
|
|
101
|
+
packages: ['@hubspot/local-dev-lib'],
|
|
102
|
+
});
|
|
103
|
+
expect(getProjectPackageJsonLocationsSpy).toHaveBeenCalledTimes(1);
|
|
104
|
+
expect(promptUserSpy).toHaveBeenCalledTimes(1);
|
|
105
|
+
expect(promptUserSpy).toHaveBeenCalledWith([
|
|
106
|
+
{
|
|
107
|
+
name: 'selectedInstallLocations',
|
|
108
|
+
type: 'checkbox',
|
|
109
|
+
when: expect.any(Function),
|
|
110
|
+
choices: [
|
|
111
|
+
{
|
|
112
|
+
name: 'directory1',
|
|
113
|
+
value: packageJsonLocation,
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
message: 'Choose which project components you would like to update the dependencies for:',
|
|
117
|
+
validate: expect.any(Function),
|
|
118
|
+
},
|
|
119
|
+
]);
|
|
120
|
+
});
|
|
121
|
+
it('should call updatePackages correctly', async () => {
|
|
122
|
+
const projectDir = 'src';
|
|
123
|
+
const packageJsonLocation = path.join(projectDir, 'directory1');
|
|
124
|
+
const installLocations = [packageJsonLocation];
|
|
125
|
+
const packages = ['@hubspot/local-dev-lib'];
|
|
126
|
+
getProjectConfigSpy.mockResolvedValue({
|
|
127
|
+
projectDir,
|
|
128
|
+
projectConfig: null,
|
|
129
|
+
});
|
|
130
|
+
promptUserSpy.mockResolvedValueOnce({
|
|
131
|
+
selectedInstallLocations: packageJsonLocation,
|
|
132
|
+
});
|
|
133
|
+
getProjectPackageJsonLocationsSpy.mockResolvedValue(installLocations);
|
|
134
|
+
await projectUpdateDepsCommand.handler({ ...args, packages });
|
|
135
|
+
expect(updatePackagesSpy).toHaveBeenCalledTimes(1);
|
|
136
|
+
expect(updatePackagesSpy).toHaveBeenCalledWith({
|
|
137
|
+
packages,
|
|
138
|
+
installLocations: packageJsonLocation,
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CommonArgs, ConfigArgs, YargsCommandModule } from '../../types/Yargs.js';
|
|
2
|
+
export type ProjectUpdateDepsArgs = CommonArgs & ConfigArgs & {
|
|
3
|
+
packages?: string[];
|
|
4
|
+
};
|
|
5
|
+
declare const projectUpdateDepsCommand: YargsCommandModule<unknown, ProjectUpdateDepsArgs>;
|
|
6
|
+
export default projectUpdateDepsCommand;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { updatePackages, getProjectPackageJsonLocations, } from '../../lib/dependencyManagement.js';
|
|
2
|
+
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
3
|
+
import { getProjectConfig } from '../../lib/projects/config.js';
|
|
4
|
+
import { promptUser } from '../../lib/prompts/promptUtils.js';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { commands } from '../../lang/en.js';
|
|
7
|
+
import { uiLogger } from '../../lib/ui/logger.js';
|
|
8
|
+
import { trackCommandUsage } from '../../lib/usageTracking.js';
|
|
9
|
+
import { logError } from '../../lib/errorHandlers/index.js';
|
|
10
|
+
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
11
|
+
const command = 'update-deps [packages..]';
|
|
12
|
+
const describe = commands.project.updateDeps.help.describe;
|
|
13
|
+
async function handler(args) {
|
|
14
|
+
const { derivedAccountId, packages } = args;
|
|
15
|
+
try {
|
|
16
|
+
trackCommandUsage('project-update-deps', undefined, derivedAccountId);
|
|
17
|
+
const projectConfig = await getProjectConfig();
|
|
18
|
+
if (!projectConfig || !projectConfig.projectDir) {
|
|
19
|
+
uiLogger.error(commands.project.updateDeps.noProjectConfig);
|
|
20
|
+
return process.exit(EXIT_CODES.ERROR);
|
|
21
|
+
}
|
|
22
|
+
const { projectDir } = projectConfig;
|
|
23
|
+
let installLocations = await getProjectPackageJsonLocations();
|
|
24
|
+
if (packages) {
|
|
25
|
+
const { selectedInstallLocations } = await promptUser([
|
|
26
|
+
{
|
|
27
|
+
name: 'selectedInstallLocations',
|
|
28
|
+
type: 'checkbox',
|
|
29
|
+
when: () => packages && packages.length > 0,
|
|
30
|
+
message: commands.project.updateDeps.installLocationPrompt,
|
|
31
|
+
choices: installLocations.map(dir => ({
|
|
32
|
+
name: path.relative(projectDir, dir),
|
|
33
|
+
value: dir,
|
|
34
|
+
})),
|
|
35
|
+
validate: (choices) => {
|
|
36
|
+
if (choices === undefined || choices.length === 0) {
|
|
37
|
+
return commands.project.updateDeps.installLocationPromptRequired;
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
]);
|
|
43
|
+
if (selectedInstallLocations) {
|
|
44
|
+
installLocations = selectedInstallLocations;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
await updatePackages({
|
|
48
|
+
packages,
|
|
49
|
+
installLocations,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
logError(e);
|
|
54
|
+
return process.exit(EXIT_CODES.ERROR);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function projectUpdateDepsBuilder(yargs) {
|
|
58
|
+
yargs.example([
|
|
59
|
+
[
|
|
60
|
+
'$0 project update-deps',
|
|
61
|
+
commands.project.updateDeps.help.updateAppDepsExample,
|
|
62
|
+
],
|
|
63
|
+
[
|
|
64
|
+
'$0 project update-deps dependency1 dependency2',
|
|
65
|
+
commands.project.updateDeps.help.updateDepToSubComponentExample,
|
|
66
|
+
],
|
|
67
|
+
]);
|
|
68
|
+
return yargs;
|
|
69
|
+
}
|
|
70
|
+
const builder = makeYargsBuilder(projectUpdateDepsBuilder, command, describe, {
|
|
71
|
+
useGlobalOptions: true,
|
|
72
|
+
useConfigOptions: true,
|
|
73
|
+
});
|
|
74
|
+
const projectUpdateDepsCommand = {
|
|
75
|
+
command,
|
|
76
|
+
describe,
|
|
77
|
+
handler,
|
|
78
|
+
builder,
|
|
79
|
+
};
|
|
80
|
+
export default projectUpdateDepsCommand;
|
package/commands/project.js
CHANGED
|
@@ -13,6 +13,7 @@ import migrate from './project/migrate.js';
|
|
|
13
13
|
import migrateApp from './project/migrateApp.js';
|
|
14
14
|
import cloneApp from './project/cloneApp.js';
|
|
15
15
|
import installDeps from './project/installDeps.js';
|
|
16
|
+
import updateDeps from './project/updateDeps.js';
|
|
16
17
|
import profile from './project/profile.js';
|
|
17
18
|
import projectValidate from './project/validate.js';
|
|
18
19
|
import list from './project/list.js';
|
|
@@ -36,6 +37,7 @@ function projectBuilder(yargs) {
|
|
|
36
37
|
.command(migrate)
|
|
37
38
|
.command(cloneApp)
|
|
38
39
|
.command(installDeps)
|
|
40
|
+
.command(updateDeps)
|
|
39
41
|
.command(profile)
|
|
40
42
|
.command(projectValidate)
|
|
41
43
|
.demandCommand(1, '');
|
|
@@ -107,7 +107,7 @@ function createTestAccountBuilder(yargs) {
|
|
|
107
107
|
});
|
|
108
108
|
yargs.example([
|
|
109
109
|
[
|
|
110
|
-
'$0 create --config-path ./test-account-config.json',
|
|
110
|
+
'$0 test-account create --config-path ./test-account-config.json',
|
|
111
111
|
commands.testAccount.create.example('./test-account-config.json'),
|
|
112
112
|
],
|
|
113
113
|
]);
|
package/lang/en.d.ts
CHANGED
|
@@ -43,14 +43,13 @@ export declare const commands: {
|
|
|
43
43
|
readonly projectCreated: {
|
|
44
44
|
readonly title: string;
|
|
45
45
|
readonly description: `Let's prepare and upload your project to HubSpot.
|
|
46
|
-
You can use ${string} to ${string}
|
|
46
|
+
You can use ${string} to ${string} your project.`;
|
|
47
47
|
};
|
|
48
48
|
};
|
|
49
49
|
readonly logs: {
|
|
50
50
|
readonly appSelected: `We'll create a new project with a sample app for you.
|
|
51
51
|
Projects are what you can use to create apps with HubSpot.
|
|
52
52
|
Usually you'll use the ${string} command, but we'll go ahead and make one now.`;
|
|
53
|
-
readonly dependenciesInstalled: "Dependencies installed successfully.";
|
|
54
53
|
readonly uploadingProject: "Uploading your project to HubSpot...";
|
|
55
54
|
readonly uploadSuccess: "Project uploaded successfully!";
|
|
56
55
|
readonly developerOverviewLink: "Open this link to navigate to your HubSpot developer portal";
|
|
@@ -58,7 +57,6 @@ Usually you'll use the ${string} command, but we'll go ahead and make one now.`;
|
|
|
58
57
|
readonly errors: {
|
|
59
58
|
readonly uploadFailed: "Failed to upload project to HubSpot.";
|
|
60
59
|
readonly configFileNotFound: "Could not find project configuration for upload.";
|
|
61
|
-
readonly installDepsFailed: "Failed to install dependencies.";
|
|
62
60
|
};
|
|
63
61
|
};
|
|
64
62
|
readonly completion: {
|
|
@@ -1382,7 +1380,7 @@ Local development of unified apps is currently only compatible with accounts tha
|
|
|
1382
1380
|
${string}`;
|
|
1383
1381
|
};
|
|
1384
1382
|
readonly prompts: {
|
|
1385
|
-
readonly parentComponents: "[--project-base]
|
|
1383
|
+
readonly parentComponents: "[--project-base] Choose what to include in your project:";
|
|
1386
1384
|
readonly emptyProject: "Empty Project";
|
|
1387
1385
|
readonly app: "App";
|
|
1388
1386
|
};
|
|
@@ -1532,7 +1530,7 @@ ${string}`;
|
|
|
1532
1530
|
readonly maxExceeded: (maxCount: number) => string;
|
|
1533
1531
|
readonly authTypeNotAllowed: (authType: string) => string;
|
|
1534
1532
|
readonly distributionNotAllowed: (dist: string) => string;
|
|
1535
|
-
readonly portalDoesNotHaveAccessToThisFeature: (
|
|
1533
|
+
readonly portalDoesNotHaveAccessToThisFeature: () => string;
|
|
1536
1534
|
readonly locationInProject: "This command must be run from within a project directory.";
|
|
1537
1535
|
readonly failedToFetchComponentList: "Failed to fetch the list of available features. Please try again later.";
|
|
1538
1536
|
readonly projectContainsPublicApp: "This project contains a public app. This command is currently only compatible with projects that contain private apps.";
|
|
@@ -1771,6 +1769,22 @@ ${string}`;
|
|
|
1771
1769
|
readonly noPackageJsonInProject: (projectName: string) => string;
|
|
1772
1770
|
readonly packageManagerNotInstalled: (packageManager: string) => string;
|
|
1773
1771
|
};
|
|
1772
|
+
readonly updateDeps: {
|
|
1773
|
+
readonly help: {
|
|
1774
|
+
readonly describe: "Update the npm dependencies for your project, or update specific dependencies in a subcomponent of a project.";
|
|
1775
|
+
readonly updateAppDepsExample: "Update the dependencies for the project";
|
|
1776
|
+
readonly updateDepToSubComponentExample: "Update the npm dependencies in one or more project subcomponents";
|
|
1777
|
+
};
|
|
1778
|
+
readonly installLocationPrompt: "Choose which project components you would like to update the dependencies for:";
|
|
1779
|
+
readonly installLocationPromptRequired: "You must choose at least one subcomponent";
|
|
1780
|
+
readonly updatingDependencies: (directory: string) => string;
|
|
1781
|
+
readonly updateSuccessful: (directory: string) => string;
|
|
1782
|
+
readonly updatingDependenciesToLocation: (dependencies: string, directory: string) => string;
|
|
1783
|
+
readonly updatingDependenciesFailed: (directory: string) => string;
|
|
1784
|
+
readonly noProjectConfig: "No project detected. Run this command from a project directory.";
|
|
1785
|
+
readonly noPackageJsonInProject: (projectName: string) => string;
|
|
1786
|
+
readonly packageManagerNotInstalled: (packageManager: string) => string;
|
|
1787
|
+
};
|
|
1774
1788
|
readonly validate: {
|
|
1775
1789
|
readonly describe: "Validate the project before uploading";
|
|
1776
1790
|
readonly mustBeRanWithinAProject: "This command must be run from within a project directory.";
|
|
@@ -2088,7 +2102,8 @@ ${string}`;
|
|
|
2088
2102
|
};
|
|
2089
2103
|
};
|
|
2090
2104
|
readonly create: {
|
|
2091
|
-
readonly describe:
|
|
2105
|
+
readonly describe: `Create a test account from scratch or from a config file. Use ${string} to generate a config file.
|
|
2106
|
+
${string}`;
|
|
2092
2107
|
readonly configPathPrompt: "[--config-path] Enter the path to the test account config: ";
|
|
2093
2108
|
readonly createTestAccountFromConfigPrompt: "How would you like to create your test account?";
|
|
2094
2109
|
readonly createFromConfigOption: "Create test account from config file";
|
|
@@ -2771,7 +2786,7 @@ export declare const lib: {
|
|
|
2771
2786
|
readonly failedToInitialize: "Missing required arguments to initialize Local Dev";
|
|
2772
2787
|
readonly noDeployedBuild: (projectName: string, accountIdentifier: string, uploadCommand: string) => string;
|
|
2773
2788
|
readonly noComponents: "There are no components in this project.";
|
|
2774
|
-
readonly
|
|
2789
|
+
readonly headerMessage: "HubSpot projects local development";
|
|
2775
2790
|
readonly learnMoreLocalDevServer: string;
|
|
2776
2791
|
readonly running: (projectName: string, accountIdentifier: string) => string;
|
|
2777
2792
|
readonly quitHelper: `Press ${string} to stop the local dev server`;
|
|
@@ -2956,8 +2971,8 @@ Run ${string} to upgrade to version ${string}`;
|
|
|
2956
2971
|
readonly prompt: {
|
|
2957
2972
|
readonly marketPlaceDistribution: "On the HubSpot marketplace";
|
|
2958
2973
|
readonly privateDistribution: "Privately";
|
|
2959
|
-
readonly distribution: "[--distribution]
|
|
2960
|
-
readonly auth: "[--auth]
|
|
2974
|
+
readonly distribution: "[--distribution] Choose how to distribute your application:";
|
|
2975
|
+
readonly auth: "[--auth] Choose your authentication type:";
|
|
2961
2976
|
readonly staticAuth: "Static Auth";
|
|
2962
2977
|
readonly oauth: "OAuth";
|
|
2963
2978
|
};
|
|
@@ -2971,7 +2986,7 @@ Run ${string} to upgrade to version ${string}`;
|
|
|
2971
2986
|
};
|
|
2972
2987
|
};
|
|
2973
2988
|
readonly add: {
|
|
2974
|
-
readonly nothingAdded: "No features added.";
|
|
2989
|
+
readonly nothingAdded: "No features were added to the project. Use the space bar to select features from the list.";
|
|
2975
2990
|
};
|
|
2976
2991
|
readonly updateHsMetaFilesWithAutoGeneratedFields: {
|
|
2977
2992
|
readonly header: "Created the following components and features:";
|
|
@@ -3364,8 +3379,8 @@ Run ${string} to upgrade to version ${string}`;
|
|
|
3364
3379
|
};
|
|
3365
3380
|
};
|
|
3366
3381
|
readonly projectNameAndDestPrompt: {
|
|
3367
|
-
readonly enterName: "[--name]
|
|
3368
|
-
readonly enterDest: "[--dest]
|
|
3382
|
+
readonly enterName: "[--name] Enter your project name:";
|
|
3383
|
+
readonly enterDest: "[--dest] Choose where to create the project:";
|
|
3369
3384
|
readonly errors: {
|
|
3370
3385
|
readonly nameRequired: "A project name is required";
|
|
3371
3386
|
readonly destRequired: "A project dest is required";
|
|
@@ -3375,7 +3390,7 @@ Run ${string} to upgrade to version ${string}`;
|
|
|
3375
3390
|
};
|
|
3376
3391
|
readonly selectProjectTemplatePrompt: {
|
|
3377
3392
|
readonly selectTemplate: "[--template] Choose a project template: ";
|
|
3378
|
-
readonly features: "[--features]
|
|
3393
|
+
readonly features: "[--features] Choose which features to add:";
|
|
3379
3394
|
readonly errors: {
|
|
3380
3395
|
readonly invalidTemplate: (template: string) => string;
|
|
3381
3396
|
readonly projectTemplateRequired: "Project template is required when projectTemplates is provided";
|
|
@@ -3409,8 +3424,8 @@ Run ${string} to upgrade to version ${string}`;
|
|
|
3409
3424
|
};
|
|
3410
3425
|
};
|
|
3411
3426
|
readonly projectAddPrompt: {
|
|
3412
|
-
readonly selectType: "[--type]
|
|
3413
|
-
readonly selectFeatures: "[--features]
|
|
3427
|
+
readonly selectType: "[--type] Choose which features to add: ";
|
|
3428
|
+
readonly selectFeatures: "[--features] Choose which features to add: ";
|
|
3414
3429
|
readonly enterName: "[--name] Give your component a name: ";
|
|
3415
3430
|
readonly errors: {
|
|
3416
3431
|
readonly nameRequired: "A component name is required";
|