@hubspot/cli 8.2.1-experimental.0 → 8.2.1-experimental.1
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/cms/function/server.js +14 -7
- package/commands/cms/theme/preview.js +8 -1
- package/commands/getStarted.js +15 -20
- package/commands/project/add.js +7 -6
- package/commands/project/appInstallStatus.js +7 -3
- package/commands/project/create.js +9 -6
- package/commands/project/deploy.js +13 -11
- package/commands/project/dev/index.js +9 -7
- package/commands/project/dev/unifiedFlow.js +8 -0
- package/commands/project/download.js +3 -3
- package/commands/project/info.js +7 -4
- package/commands/project/installApp.js +8 -3
- package/commands/project/installDeps.js +6 -5
- package/commands/project/lint.js +16 -9
- package/commands/project/listBuilds.d.ts +3 -2
- package/commands/project/listBuilds.js +40 -13
- package/commands/project/migrate.js +14 -12
- package/commands/project/open.js +15 -7
- package/commands/project/profile/add.js +8 -4
- package/commands/project/profile/delete.js +8 -4
- package/commands/project/release/create.js +4 -6
- package/commands/project/release/info.js +3 -3
- package/commands/project/release/list.js +3 -3
- package/commands/project/updateDeps.js +6 -5
- package/commands/project/upload.js +26 -15
- package/commands/project/validate.js +14 -97
- package/commands/project/watch.js +8 -11
- package/commands/project.js +1 -1
- package/lang/en.d.ts +19 -18
- package/lang/en.js +23 -20
- package/lib/app/migrate.js +5 -7
- package/lib/cms/serverlessDevRuntime.d.ts +1 -0
- package/lib/cms/serverlessDevRuntime.js +72 -0
- package/lib/constants.d.ts +2 -0
- package/lib/constants.js +2 -0
- package/lib/dependencyManagement.js +3 -10
- package/lib/doctor/DiagnosticInfoBuilder.d.ts +2 -2
- package/lib/doctor/DiagnosticInfoBuilder.js +8 -8
- package/lib/doctor/Doctor.js +7 -9
- package/lib/errors/ProjectErrors.d.ts +0 -6
- package/lib/errors/ProjectErrors.js +0 -12
- package/lib/errors/ProjectValidationError.d.ts +2 -1
- package/lib/errors/ProjectValidationError.js +3 -1
- package/lib/getStartedV2Actions.js +14 -18
- package/lib/jsonOutput.d.ts +86 -0
- package/lib/jsonOutput.js +77 -0
- package/lib/npm/packageJson.js +1 -1
- package/lib/projects/ProjectLogsManager.js +1 -4
- package/lib/projects/config.d.ts +6 -5
- package/lib/projects/config.js +7 -38
- package/lib/projects/localDev/LocalDevLogger.d.ts +4 -0
- package/lib/projects/localDev/LocalDevLogger.js +18 -0
- package/lib/projects/localDev/LocalDevProcess.d.ts +11 -1
- package/lib/projects/localDev/LocalDevProcess.js +91 -9
- package/lib/projects/localDev/LocalDevState.d.ts +7 -1
- package/lib/projects/localDev/LocalDevState.js +19 -1
- package/lib/projects/localDev/LocalDevWatcher.js +1 -1
- package/lib/projects/localDev/LocalDevWebsocketServer.d.ts +1 -0
- package/lib/projects/localDev/LocalDevWebsocketServer.js +23 -1
- package/lib/projects/localDev/localDevWebsocketServerUtils.d.ts +2 -1
- package/lib/projects/localDev/localDevWebsocketServerUtils.js +3 -0
- package/lib/projects/projectProfiles.d.ts +2 -2
- package/lib/projects/projectProfiles.js +0 -3
- package/lib/projects/release.js +1 -1
- package/lib/projects/uieLinting.js +0 -3
- package/lib/projects/validate.d.ts +9 -0
- package/lib/projects/validate.js +96 -0
- package/lib/theme/migrate.js +1 -4
- package/mcp-server/tools/project/GetBuildLogsTool.js +2 -3
- package/mcp-server/tools/project/GetBuildStatusTool.js +2 -3
- package/mcp-server/tools/project/UploadProjectTools.js +3 -5
- package/package.json +11 -10
- package/types/LocalDev.d.ts +7 -0
- package/types/Projects.d.ts +1 -5
- package/types/Yargs.d.ts +1 -0
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
import { uiLogger } from '../../../lib/ui/logger.js';
|
|
2
|
-
// This package is not typed, so we need to use require
|
|
3
|
-
import { start as startTestServer } from '@hubspot/serverless-dev-runtime';
|
|
4
2
|
import { commands } from '../../../lang/en.js';
|
|
3
|
+
import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
|
|
4
|
+
import { startServerlessDevRuntime } from '../../../lib/cms/serverlessDevRuntime.js';
|
|
5
|
+
import { logError } from '../../../lib/errorHandlers/index.js';
|
|
5
6
|
import { makeWrappedYargsHandler } from '../../../lib/yargs/makeWrappedYargsHandler.js';
|
|
6
7
|
import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
|
|
7
8
|
const command = 'server <path>';
|
|
8
9
|
const describe = undefined;
|
|
9
10
|
async function handler(args) {
|
|
10
|
-
const { path: functionPath, derivedAccountId } = args;
|
|
11
|
+
const { path: functionPath, derivedAccountId, exit } = args;
|
|
11
12
|
uiLogger.debug(commands.cms.subcommands.function.subcommands.server.debug.startingServer(functionPath));
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
try {
|
|
14
|
+
await startServerlessDevRuntime({
|
|
15
|
+
accountId: derivedAccountId,
|
|
16
|
+
...args,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
logError(e);
|
|
21
|
+
return exit(EXIT_CODES.ERROR);
|
|
22
|
+
}
|
|
16
23
|
}
|
|
17
24
|
function functionServerBuilder(yargs) {
|
|
18
25
|
yargs.positional('path', {
|
|
@@ -35,7 +35,14 @@ function validateSrcPath(src) {
|
|
|
35
35
|
async function determineSrcAndDest(args) {
|
|
36
36
|
let absoluteSrc;
|
|
37
37
|
let dest;
|
|
38
|
-
|
|
38
|
+
let projectDir;
|
|
39
|
+
let projectConfig;
|
|
40
|
+
try {
|
|
41
|
+
({ projectDir, projectConfig } = getProjectConfig());
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Not in a project (handled below)
|
|
45
|
+
}
|
|
39
46
|
if (!(projectDir && projectConfig)) {
|
|
40
47
|
// Not in a project, prompt for src and dest of traditional theme
|
|
41
48
|
const previewPromptAnswers = await previewPrompt(args);
|
package/commands/getStarted.js
CHANGED
|
@@ -7,7 +7,7 @@ import { commands } from '../lang/en.js';
|
|
|
7
7
|
import { GET_STARTED_OPTIONS, HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, PROJECT_CONFIG_FILE, } from '../lib/constants.js';
|
|
8
8
|
import { EXIT_CODES } from '../lib/enums/exitCodes.js';
|
|
9
9
|
import { debugError, logError } from '../lib/errorHandlers/index.js';
|
|
10
|
-
import { getProjectConfig,
|
|
10
|
+
import { getProjectConfig, writeProjectConfig, ProjectConfigValidationError, } from '../lib/projects/config.js';
|
|
11
11
|
import { handleProjectUpload } from '../lib/projects/upload.js';
|
|
12
12
|
import { projectNameAndDestPrompt } from '../lib/prompts/projectNameAndDestPrompt.js';
|
|
13
13
|
import { promptUser } from '../lib/prompts/promptUtils.js';
|
|
@@ -20,7 +20,6 @@ import { pollProjectBuildAndDeploy } from '../lib/projects/pollProjectBuildAndDe
|
|
|
20
20
|
import { fetchPublicAppsForPortal } from '@hubspot/local-dev-lib/api/appsDev';
|
|
21
21
|
import { getConfigAccountEnvironment } from '@hubspot/local-dev-lib/config';
|
|
22
22
|
import { getStaticAuthAppInstallUrl } from '../lib/app/urls.js';
|
|
23
|
-
import ProjectValidationError from '../lib/errors/ProjectValidationError.js';
|
|
24
23
|
import { openLink } from '../lib/links.js';
|
|
25
24
|
import { runGetStartedV2 } from '../lib/getStarted/getStartedV2.js';
|
|
26
25
|
import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
|
|
@@ -98,10 +97,14 @@ async function handler(args) {
|
|
|
98
97
|
uiLogger.log(commands.getStarted.logs.appSelected);
|
|
99
98
|
const { dest, name } = await projectNameAndDestPrompt(args);
|
|
100
99
|
const projectDest = path.resolve(getCwd(), dest);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
existingProjectDir
|
|
104
|
-
|
|
100
|
+
let existingProjectDir;
|
|
101
|
+
try {
|
|
102
|
+
existingProjectDir = getProjectConfig(projectDest).projectDir;
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Not in a project directory
|
|
106
|
+
}
|
|
107
|
+
if (existingProjectDir && projectDest.startsWith(existingProjectDir)) {
|
|
105
108
|
// Track nested project error
|
|
106
109
|
await trackCommandMetadataUsage('get-started', {
|
|
107
110
|
successful: false,
|
|
@@ -167,29 +170,21 @@ async function handler(args) {
|
|
|
167
170
|
if (shouldUpload) {
|
|
168
171
|
try {
|
|
169
172
|
// Get the project config for the newly created project
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
// Track config file not found error
|
|
173
|
-
await trackCommandMetadataUsage('get-started', {
|
|
174
|
-
successful: false,
|
|
175
|
-
step: 'config-file-not-found',
|
|
176
|
-
}, derivedAccountId);
|
|
177
|
-
uiLogger.log(' ');
|
|
178
|
-
uiLogger.error(commands.getStarted.errors.configFileNotFound);
|
|
179
|
-
return exit(EXIT_CODES.ERROR);
|
|
180
|
-
}
|
|
173
|
+
let newProjectConfig;
|
|
174
|
+
let newProjectDir;
|
|
181
175
|
try {
|
|
182
|
-
|
|
176
|
+
({ projectConfig: newProjectConfig, projectDir: newProjectDir } =
|
|
177
|
+
getProjectConfig(projectDest));
|
|
183
178
|
}
|
|
184
179
|
catch (error) {
|
|
185
|
-
if (error instanceof
|
|
180
|
+
if (error instanceof ProjectConfigValidationError) {
|
|
186
181
|
// Track validation error
|
|
187
182
|
await trackCommandMetadataUsage('get-started', {
|
|
188
183
|
successful: false,
|
|
189
184
|
step: 'project-validation-failed',
|
|
190
185
|
}, derivedAccountId);
|
|
191
186
|
uiLogger.log(' ');
|
|
192
|
-
uiLogger.error(error.message);
|
|
187
|
+
uiLogger.error(error.message || commands.getStarted.errors.configFileNotFound);
|
|
193
188
|
return exit(EXIT_CODES.ERROR);
|
|
194
189
|
}
|
|
195
190
|
throw error;
|
package/commands/project/add.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { logError } from '../../lib/errorHandlers/index.js';
|
|
2
|
-
import { getProjectConfig } from '../../lib/projects/config.js';
|
|
2
|
+
import { getIsInProject, getProjectConfig } from '../../lib/projects/config.js';
|
|
3
3
|
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
4
4
|
import { isPromptExitError } from '../../lib/errors/PromptExitError.js';
|
|
5
5
|
import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler.js';
|
|
@@ -14,12 +14,13 @@ const command = 'add';
|
|
|
14
14
|
const describe = commands.project.add.describe;
|
|
15
15
|
async function handler(args) {
|
|
16
16
|
const { derivedAccountId, exit } = args;
|
|
17
|
+
const isInProjectDir = getIsInProject();
|
|
18
|
+
if (!isInProjectDir) {
|
|
19
|
+
uiLogger.error(commands.project.add.error.locationInProject);
|
|
20
|
+
return exit(EXIT_CODES.ERROR);
|
|
21
|
+
}
|
|
17
22
|
try {
|
|
18
|
-
const { projectConfig, projectDir } =
|
|
19
|
-
if (!projectDir || !projectConfig) {
|
|
20
|
-
uiLogger.error(commands.project.add.error.locationInProject);
|
|
21
|
-
return exit(EXIT_CODES.ERROR);
|
|
22
|
-
}
|
|
23
|
+
const { projectConfig, projectDir } = getProjectConfig();
|
|
23
24
|
const isLegacyProjectCreate = isLegacyProject(projectConfig.platformVersion);
|
|
24
25
|
if (!isLegacyProjectCreate) {
|
|
25
26
|
await v2AddComponent(args, projectDir, projectConfig, derivedAccountId);
|
|
@@ -18,9 +18,13 @@ const command = 'app-install-status';
|
|
|
18
18
|
const describe = commands.project.installStatus.describe;
|
|
19
19
|
async function handler(args) {
|
|
20
20
|
const { derivedAccountId, formatOutputAsJson, exit, addJsonOutput } = args;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
let projectConfig;
|
|
22
|
+
let projectDir;
|
|
23
|
+
try {
|
|
24
|
+
({ projectConfig, projectDir } = getProjectConfig());
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
logError(error);
|
|
24
28
|
return exit(EXIT_CODES.ERROR);
|
|
25
29
|
}
|
|
26
30
|
if (isLegacyProject(projectConfig.platformVersion)) {
|
|
@@ -51,13 +51,16 @@ async function handler(args) {
|
|
|
51
51
|
.join(','),
|
|
52
52
|
});
|
|
53
53
|
const projectDest = path.resolve(getCwd(), projectNameAndDestPromptResponse.dest);
|
|
54
|
-
const { projectConfig: existingProjectConfig, projectDir: existingProjectDir, } = await getProjectConfig(projectDest);
|
|
55
54
|
// Exit if the target destination is within an existing project
|
|
56
|
-
|
|
57
|
-
existingProjectDir
|
|
58
|
-
projectDest.startsWith(existingProjectDir)) {
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
try {
|
|
56
|
+
const { projectDir: existingProjectDir } = getProjectConfig(projectDest);
|
|
57
|
+
if (projectDest.startsWith(existingProjectDir)) {
|
|
58
|
+
uiLogger.error(commands.project.create.errors.cannotNestProjects(existingProjectDir));
|
|
59
|
+
return exit(EXIT_CODES.ERROR);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// Not in a project directory, which is the expected case for create
|
|
61
64
|
}
|
|
62
65
|
const components = generateComponentPaths({
|
|
63
66
|
selectProjectTemplatePromptResponse,
|
|
@@ -3,7 +3,7 @@ import { getConfigAccountById } from '@hubspot/local-dev-lib/config';
|
|
|
3
3
|
import { isSpecifiedError } from '@hubspot/local-dev-lib/errors/index';
|
|
4
4
|
import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
|
|
5
5
|
import { logError, ApiErrorContext } from '../../lib/errorHandlers/index.js';
|
|
6
|
-
import { getProjectConfig
|
|
6
|
+
import { getProjectConfig } from '../../lib/projects/config.js';
|
|
7
7
|
import { projectNamePrompt } from '../../lib/prompts/projectNamePrompt.js';
|
|
8
8
|
import { projectProfilePrompt } from '../../lib/prompts/projectProfilePrompt.js';
|
|
9
9
|
import { promptUser } from '../../lib/prompts/promptUtils.js';
|
|
@@ -25,22 +25,24 @@ async function handler(args) {
|
|
|
25
25
|
const accountConfig = getConfigAccountById(derivedAccountId);
|
|
26
26
|
const accountType = accountConfig && accountConfig.accountType;
|
|
27
27
|
let targetAccountId;
|
|
28
|
-
|
|
28
|
+
let loadedConfig;
|
|
29
29
|
let isInProjectDirectory = false;
|
|
30
|
-
// Validate project config, but it's valid to run this command from outside a project dir
|
|
31
30
|
try {
|
|
32
|
-
|
|
31
|
+
loadedConfig = getProjectConfig();
|
|
33
32
|
isInProjectDirectory = true;
|
|
34
33
|
}
|
|
35
|
-
catch (e) {
|
|
34
|
+
catch (e) {
|
|
35
|
+
// Do nothing, it's valid to run this command from outside a project dir
|
|
36
|
+
}
|
|
36
37
|
if (isInProjectDirectory &&
|
|
37
|
-
|
|
38
|
+
loadedConfig &&
|
|
39
|
+
!isLegacyProject(loadedConfig.projectConfig.platformVersion)) {
|
|
38
40
|
try {
|
|
39
|
-
const profileName = await projectProfilePrompt(projectDir, projectConfig, profileOption, !!useEnvOption);
|
|
41
|
+
const profileName = await projectProfilePrompt(loadedConfig.projectDir, loadedConfig.projectConfig, profileOption, !!useEnvOption);
|
|
40
42
|
if (profileName) {
|
|
41
43
|
// Use loadProfile instead of loadAndValidateProfile because the local
|
|
42
44
|
// profile does not need to be valid to successfully deploy
|
|
43
|
-
const profile = loadProfile(projectConfig, projectDir, profileName);
|
|
45
|
+
const profile = loadProfile(loadedConfig.projectConfig, loadedConfig.projectDir, profileName);
|
|
44
46
|
targetAccountId = profile.accountId;
|
|
45
47
|
uiLogger.log(commands.project.deploy.profileMessage(profileName, targetAccountId));
|
|
46
48
|
uiLogger.log('');
|
|
@@ -58,8 +60,8 @@ async function handler(args) {
|
|
|
58
60
|
addUsageMetadata({ type: accountType });
|
|
59
61
|
}
|
|
60
62
|
let projectName = projectOption;
|
|
61
|
-
if (!projectOption &&
|
|
62
|
-
projectName = projectConfig.name;
|
|
63
|
+
if (!projectOption && loadedConfig) {
|
|
64
|
+
projectName = loadedConfig.projectConfig.name;
|
|
63
65
|
}
|
|
64
66
|
const namePromptResponse = await projectNamePrompt(targetAccountId, {
|
|
65
67
|
project: projectName,
|
|
@@ -116,7 +118,7 @@ async function handler(args) {
|
|
|
116
118
|
catch {
|
|
117
119
|
return exit(EXIT_CODES.ERROR);
|
|
118
120
|
}
|
|
119
|
-
const deployResult = await handleProjectDeploy(targetAccountId, projectName, buildIdToDeploy, isLegacyProject(projectConfig
|
|
121
|
+
const deployResult = await handleProjectDeploy(targetAccountId, projectName, buildIdToDeploy, isLegacyProject(loadedConfig?.projectConfig.platformVersion), forceOption);
|
|
120
122
|
if (!deployResult) {
|
|
121
123
|
return exit(EXIT_CODES.ERROR);
|
|
122
124
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getConfigAccountIfExists } from '@hubspot/local-dev-lib/config';
|
|
2
|
-
import { getProjectConfig
|
|
2
|
+
import { getProjectConfig } from '../../../lib/projects/config.js';
|
|
3
3
|
import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
|
|
4
4
|
import { uiLine } from '../../../lib/ui/index.js';
|
|
5
5
|
import { makeWrappedYargsHandler } from '../../../lib/yargs/makeWrappedYargsHandler.js';
|
|
@@ -17,18 +17,15 @@ const command = 'dev';
|
|
|
17
17
|
const describe = commands.project.dev.describe;
|
|
18
18
|
async function handler(args) {
|
|
19
19
|
const { derivedAccountId, testingAccount, projectAccount, profile: profileOption, exit, addUsageMetadata, } = args;
|
|
20
|
-
|
|
20
|
+
let projectConfig;
|
|
21
|
+
let projectDir;
|
|
21
22
|
try {
|
|
22
|
-
|
|
23
|
+
({ projectConfig, projectDir } = getProjectConfig());
|
|
23
24
|
}
|
|
24
25
|
catch (error) {
|
|
25
26
|
logError(error);
|
|
26
27
|
return exit(EXIT_CODES.ERROR);
|
|
27
28
|
}
|
|
28
|
-
if (!projectDir) {
|
|
29
|
-
uiLogger.error(commands.project.dev.errors.noProjectConfig);
|
|
30
|
-
return exit(EXIT_CODES.ERROR);
|
|
31
|
-
}
|
|
32
29
|
if (isLegacyProject(projectConfig.platformVersion)) {
|
|
33
30
|
uiLogger.error(commands.project.dev.errors.unsupportedPlatformVersion(projectConfig.platformVersion));
|
|
34
31
|
return exit(EXIT_CODES.ERROR);
|
|
@@ -110,6 +107,11 @@ function projectDevBuilder(yargs) {
|
|
|
110
107
|
description: commands.project.dev.options.port,
|
|
111
108
|
default: LOCAL_DEV_DEFAULT_PORT,
|
|
112
109
|
});
|
|
110
|
+
yargs.option('auto-upload', {
|
|
111
|
+
type: 'boolean',
|
|
112
|
+
description: commands.project.dev.options.autoUpload,
|
|
113
|
+
default: false,
|
|
114
|
+
});
|
|
113
115
|
yargs.example([['$0 project dev', commands.project.dev.examples.default]]);
|
|
114
116
|
yargs.conflicts('profile', 'testing-account');
|
|
115
117
|
yargs.conflicts('profile', 'project-account');
|
|
@@ -155,6 +155,13 @@ export async function unifiedProjectDevFlow({ args, targetProjectAccountId, prov
|
|
|
155
155
|
noLogs: true,
|
|
156
156
|
});
|
|
157
157
|
let project = uploadedProject;
|
|
158
|
+
// Fail fast before the slower project checks below.
|
|
159
|
+
const autoDeployEnabled = (project?.deployedBuild ?? project?.latestBuild)?.isAutoDeployEnabled ??
|
|
160
|
+
true;
|
|
161
|
+
if (args.autoUpload && !autoDeployEnabled) {
|
|
162
|
+
uiLogger.error(commands.project.dev.errors.autoUploadRequiresAutoDeploy);
|
|
163
|
+
return exit(EXIT_CODES.ERROR);
|
|
164
|
+
}
|
|
158
165
|
if (projectExists && project) {
|
|
159
166
|
await compareLocalProjectToDeployed(projectConfig, targetProjectAccountId, project.deployedBuild?.buildId, projectNodes, exit, args.profile);
|
|
160
167
|
}
|
|
@@ -189,6 +196,7 @@ export async function unifiedProjectDevFlow({ args, targetProjectAccountId, prov
|
|
|
189
196
|
projectData: project,
|
|
190
197
|
env,
|
|
191
198
|
actions: { exit },
|
|
199
|
+
autoUploadEnabled: Boolean(args.autoUpload) && autoDeployEnabled,
|
|
192
200
|
});
|
|
193
201
|
const websocketServer = new LocalDevWebsocketServer(localDevProcess, args.debug);
|
|
194
202
|
const watcher = new LocalDevWatcher(localDevProcess);
|
|
@@ -4,7 +4,7 @@ import { extractZipArchive } from '@hubspot/local-dev-lib/archive';
|
|
|
4
4
|
import { downloadProject, fetchProjectBuilds, } from '@hubspot/local-dev-lib/api/projects';
|
|
5
5
|
import { logError, ApiErrorContext } from '../../lib/errorHandlers/index.js';
|
|
6
6
|
import { isPromptExitError } from '../../lib/errors/PromptExitError.js';
|
|
7
|
-
import {
|
|
7
|
+
import { getIsInProject } from '../../lib/projects/config.js';
|
|
8
8
|
import { downloadProjectPrompt } from '../../lib/prompts/downloadProjectPrompt.js';
|
|
9
9
|
import { commands } from '../../lang/en.js';
|
|
10
10
|
import { uiLogger } from '../../lib/ui/logger.js';
|
|
@@ -15,8 +15,8 @@ const command = 'download';
|
|
|
15
15
|
const describe = commands.project.download.describe;
|
|
16
16
|
async function handler(args) {
|
|
17
17
|
const { dest, build, derivedAccountId, exit } = args;
|
|
18
|
-
const
|
|
19
|
-
if (
|
|
18
|
+
const isInProjectDir = getIsInProject();
|
|
19
|
+
if (isInProjectDir) {
|
|
20
20
|
uiLogger.error(commands.project.download.warnings.cannotDownloadWithinProject);
|
|
21
21
|
return exit(EXIT_CODES.ERROR);
|
|
22
22
|
}
|
package/commands/project/info.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler.js';
|
|
2
2
|
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
3
3
|
import { fetchProject } from '@hubspot/local-dev-lib/api/projects';
|
|
4
|
-
import { debugError } from '../../lib/errorHandlers/index.js';
|
|
4
|
+
import { debugError, logError } from '../../lib/errorHandlers/index.js';
|
|
5
5
|
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
6
6
|
import { uiLogger } from '../../lib/ui/logger.js';
|
|
7
7
|
import { commands } from '../../lang/en.js';
|
|
@@ -14,9 +14,12 @@ const describe = commands.project.info.describe;
|
|
|
14
14
|
const verboseDescribe = commands.project.info.verboseDescribe;
|
|
15
15
|
async function handler(args) {
|
|
16
16
|
const { derivedAccountId, formatOutputAsJson, exit, addJsonOutput } = args;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
let projectConfig;
|
|
18
|
+
try {
|
|
19
|
+
({ projectConfig } = getProjectConfig());
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
logError(error);
|
|
20
23
|
return exit(EXIT_CODES.ERROR);
|
|
21
24
|
}
|
|
22
25
|
if (isLegacyProject(projectConfig.platformVersion)) {
|
|
@@ -4,6 +4,7 @@ import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler
|
|
|
4
4
|
import { InstallAppSchema, } from '../../lib/jsonOutput.js';
|
|
5
5
|
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
6
6
|
import { uiLogger } from '../../lib/ui/logger.js';
|
|
7
|
+
import { logError } from '../../lib/errorHandlers/index.js';
|
|
7
8
|
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
8
9
|
import { commands } from '../../lang/en.js';
|
|
9
10
|
import { getProjectConfig } from '../../lib/projects/config.js';
|
|
@@ -15,9 +16,13 @@ const describe = commands.project.installApp.describe;
|
|
|
15
16
|
const verboseDescribe = commands.project.installApp.verboseDescribe;
|
|
16
17
|
async function handler(args) {
|
|
17
18
|
const { derivedAccountId, formatOutputAsJson, force, profile: profileOption, useEnv: useEnvOption, exit, addJsonOutput, } = args;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
let projectConfig;
|
|
20
|
+
let projectDir;
|
|
21
|
+
try {
|
|
22
|
+
({ projectConfig, projectDir } = getProjectConfig());
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
logError(error);
|
|
21
26
|
return exit(EXIT_CODES.ERROR);
|
|
22
27
|
}
|
|
23
28
|
if (isLegacyProject(projectConfig.platformVersion)) {
|
|
@@ -5,7 +5,6 @@ import { getProjectConfig } from '../../lib/projects/config.js';
|
|
|
5
5
|
import { promptUser } from '../../lib/prompts/promptUtils.js';
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import { commands } from '../../lang/en.js';
|
|
8
|
-
import { uiLogger } from '../../lib/ui/logger.js';
|
|
9
8
|
import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler.js';
|
|
10
9
|
import { logError } from '../../lib/errorHandlers/index.js';
|
|
11
10
|
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
@@ -15,12 +14,14 @@ const describe = commands.project.installDeps.help.describe;
|
|
|
15
14
|
async function handler(args) {
|
|
16
15
|
const { packages, exit } = args;
|
|
17
16
|
try {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
let projectDir;
|
|
18
|
+
try {
|
|
19
|
+
({ projectDir } = getProjectConfig());
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
logError(error);
|
|
21
23
|
return exit(EXIT_CODES.ERROR);
|
|
22
24
|
}
|
|
23
|
-
const { projectDir } = projectConfig;
|
|
24
25
|
let installLocations = await getProjectPackageJsonLocations();
|
|
25
26
|
if (packages) {
|
|
26
27
|
const { selectedInstallLocations } = await promptUser([
|
package/commands/project/lint.js
CHANGED
|
@@ -17,16 +17,23 @@ const describe = commands.project.lint.help.describe;
|
|
|
17
17
|
async function handler(args) {
|
|
18
18
|
const { installMissingDeps, exit } = args;
|
|
19
19
|
try {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
let projectConfig;
|
|
21
|
+
let projectDir;
|
|
22
|
+
try {
|
|
23
|
+
({ projectConfig, projectDir } = getProjectConfig());
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
logError(error);
|
|
23
27
|
return exit(EXIT_CODES.ERROR);
|
|
24
28
|
}
|
|
25
29
|
SpinniesManager.init({ succeedColor: 'white' });
|
|
26
30
|
SpinniesManager.add('lintCheck', {
|
|
27
31
|
text: commands.project.lint.loading.checking,
|
|
28
32
|
});
|
|
29
|
-
const lintLocations = await getUieLintablePackageJsonLocations(
|
|
33
|
+
const lintLocations = await getUieLintablePackageJsonLocations({
|
|
34
|
+
projectConfig,
|
|
35
|
+
projectDir,
|
|
36
|
+
});
|
|
30
37
|
const locationsReadyToLint = [];
|
|
31
38
|
const locationsNeedingPackages = new Map();
|
|
32
39
|
let skippedDirectoryCount = 0;
|
|
@@ -44,7 +51,7 @@ async function handler(args) {
|
|
|
44
51
|
SpinniesManager.succeed('lintCheck');
|
|
45
52
|
if (locationsNeedingPackages.size > 0) {
|
|
46
53
|
const locationsArray = Array.from(locationsNeedingPackages.keys());
|
|
47
|
-
const relativeLocations = locationsArray.map(loc => path.relative(
|
|
54
|
+
const relativeLocations = locationsArray.map(loc => path.relative(projectDir, loc));
|
|
48
55
|
const allMissingPackages = [];
|
|
49
56
|
for (const packages of locationsNeedingPackages.values()) {
|
|
50
57
|
allMissingPackages.push(...packages);
|
|
@@ -94,7 +101,7 @@ async function handler(args) {
|
|
|
94
101
|
const hasModernConfig = hasEslintConfig(location);
|
|
95
102
|
const hasDeprecatedConfig = hasDeprecatedEslintConfig(location);
|
|
96
103
|
if (hasDeprecatedConfig) {
|
|
97
|
-
const relativePath = path.relative(
|
|
104
|
+
const relativePath = path.relative(projectDir, location);
|
|
98
105
|
const deprecatedFiles = getDeprecatedEslintConfigFiles(location);
|
|
99
106
|
deprecatedConfigDetails.push({
|
|
100
107
|
path: relativePath,
|
|
@@ -110,7 +117,7 @@ async function handler(args) {
|
|
|
110
117
|
uiLogger.warn(commands.project.lint.deprecatedEslintConfigWarning(deprecatedConfigDetails));
|
|
111
118
|
}
|
|
112
119
|
if (locationsNeedingConfig.length > 0) {
|
|
113
|
-
const relativeLocations = locationsNeedingConfig.map(loc => path.relative(
|
|
120
|
+
const relativeLocations = locationsNeedingConfig.map(loc => path.relative(projectDir, loc));
|
|
114
121
|
const { shouldCreateConfig } = await promptUser([
|
|
115
122
|
{
|
|
116
123
|
name: 'shouldCreateConfig',
|
|
@@ -123,7 +130,7 @@ async function handler(args) {
|
|
|
123
130
|
SpinniesManager.add('lintConfigCreate', {
|
|
124
131
|
text: commands.project.lint.loading.creatingConfig,
|
|
125
132
|
});
|
|
126
|
-
const platformVersion = projectConfig.
|
|
133
|
+
const platformVersion = projectConfig.platformVersion ?? null;
|
|
127
134
|
const createdConfigs = [];
|
|
128
135
|
for (const location of locationsNeedingConfig) {
|
|
129
136
|
const configPath = await createEslintConfig(location, platformVersion);
|
|
@@ -159,7 +166,7 @@ async function handler(args) {
|
|
|
159
166
|
SpinniesManager.add('lintRun', {
|
|
160
167
|
text: commands.project.lint.loading.linting,
|
|
161
168
|
});
|
|
162
|
-
const { success, results } = await lintPackages(locationsReadyToLint,
|
|
169
|
+
const { success, results } = await lintPackages(locationsReadyToLint, projectDir);
|
|
163
170
|
SpinniesManager.succeed('lintRun');
|
|
164
171
|
displayLintResults(results);
|
|
165
172
|
if (!success) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { CommonArgs, ConfigArgs, AccountArgs, EnvironmentArgs, YargsCommandModule } from '../../types/Yargs.js';
|
|
2
|
-
|
|
1
|
+
import { CommonArgs, ConfigArgs, AccountArgs, EnvironmentArgs, JSONOutputArgs, YargsCommandModule } from '../../types/Yargs.js';
|
|
2
|
+
import { ProjectBuildsListJsonOutput } from '../../lib/jsonOutput.js';
|
|
3
|
+
export type ProjectListBuildsArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs<ProjectBuildsListJsonOutput> & {
|
|
3
4
|
project?: string;
|
|
4
5
|
limit?: number;
|
|
5
6
|
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
|
|
2
2
|
import { fetchProject, fetchProjectBuilds, } from '@hubspot/local-dev-lib/api/projects';
|
|
3
3
|
import { uiLink } from '../../lib/ui/index.js';
|
|
4
|
-
import { getProjectConfig
|
|
4
|
+
import { getProjectConfig } from '../../lib/projects/config.js';
|
|
5
5
|
import { getProjectDetailUrl } from '../../lib/projects/urls.js';
|
|
6
6
|
import moment from 'moment';
|
|
7
7
|
import { promptUser } from '../../lib/prompts/promptUtils.js';
|
|
8
|
+
import { isPromptExitError } from '../../lib/errors/PromptExitError.js';
|
|
8
9
|
import { uiLogger } from '../../lib/ui/logger.js';
|
|
9
10
|
import { logError, ApiErrorContext } from '../../lib/errorHandlers/index.js';
|
|
10
11
|
import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler.js';
|
|
@@ -12,6 +13,7 @@ import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
|
12
13
|
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
13
14
|
import { commands } from '../../lang/en.js';
|
|
14
15
|
import { renderTable } from '../../ui/render.js';
|
|
16
|
+
import { ProjectBuildsListSchema, mapBuildToJsonOutput, } from '../../lib/jsonOutput.js';
|
|
15
17
|
const command = 'list-builds';
|
|
16
18
|
const describe = commands.project.listBuilds.describe;
|
|
17
19
|
async function fetchAndDisplayBuilds(accountId, project, options) {
|
|
@@ -40,7 +42,7 @@ async function fetchAndDisplayBuilds(accountId, project, options) {
|
|
|
40
42
|
});
|
|
41
43
|
renderTable(['Build ID', 'Status', 'Completed', 'Duration', 'Details'], builds);
|
|
42
44
|
}
|
|
43
|
-
if (options
|
|
45
|
+
if (options.after) {
|
|
44
46
|
if (results.length > 0) {
|
|
45
47
|
uiLogger.log(commands.project.listBuilds.showingNextBuilds(results.length, project.name));
|
|
46
48
|
}
|
|
@@ -48,7 +50,8 @@ async function fetchAndDisplayBuilds(accountId, project, options) {
|
|
|
48
50
|
else {
|
|
49
51
|
uiLogger.log(commands.project.listBuilds.showingRecentBuilds(results.length, project.name, uiLink(commands.project.listBuilds.viewAllBuildsLink, getProjectDetailUrl(project.name, accountId))));
|
|
50
52
|
}
|
|
51
|
-
|
|
53
|
+
const canPromptForMore = options.limit === undefined && Boolean(process.stdin.isTTY);
|
|
54
|
+
if (paging?.next?.after && canPromptForMore) {
|
|
52
55
|
await promptUser({
|
|
53
56
|
name: 'more',
|
|
54
57
|
message: commands.project.listBuilds.continueOrExitPrompt,
|
|
@@ -60,27 +63,39 @@ async function fetchAndDisplayBuilds(accountId, project, options) {
|
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
65
|
async function handler(args) {
|
|
63
|
-
const { project: projectFlagValue, limit, derivedAccountId, exit } = args;
|
|
66
|
+
const { project: projectFlagValue, limit, derivedAccountId, exit, json: formatOutputAsJson, addJsonOutput, } = args;
|
|
64
67
|
let projectName = projectFlagValue;
|
|
65
68
|
if (!projectName) {
|
|
66
|
-
const { projectConfig, projectDir } = await getProjectConfig();
|
|
67
69
|
try {
|
|
68
|
-
|
|
70
|
+
const { projectConfig } = getProjectConfig();
|
|
71
|
+
projectName = projectConfig.name;
|
|
69
72
|
}
|
|
70
73
|
catch (error) {
|
|
71
74
|
logError(error);
|
|
72
75
|
return exit(EXIT_CODES.ERROR);
|
|
73
76
|
}
|
|
74
|
-
if (!projectConfig) {
|
|
75
|
-
return exit(EXIT_CODES.ERROR);
|
|
76
|
-
}
|
|
77
|
-
projectName = projectConfig.name;
|
|
78
77
|
}
|
|
79
78
|
try {
|
|
80
79
|
const { data: project } = await fetchProject(derivedAccountId, projectName);
|
|
81
|
-
|
|
80
|
+
if (formatOutputAsJson) {
|
|
81
|
+
const { data: { results, paging }, } = await fetchProjectBuilds(derivedAccountId, project.name, { limit });
|
|
82
|
+
addJsonOutput({
|
|
83
|
+
projectName: project.name,
|
|
84
|
+
deployedBuildId: project.deployedBuildId,
|
|
85
|
+
results: results.map(build => mapBuildToJsonOutput(build, project.deployedBuildId)),
|
|
86
|
+
paging: paging?.next?.after
|
|
87
|
+
? { next: { after: paging.next.after } }
|
|
88
|
+
: undefined,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
await fetchAndDisplayBuilds(derivedAccountId, project, { limit });
|
|
93
|
+
}
|
|
82
94
|
}
|
|
83
95
|
catch (e) {
|
|
96
|
+
if (isPromptExitError(e)) {
|
|
97
|
+
return exit(e.exitCode);
|
|
98
|
+
}
|
|
84
99
|
if (isHubSpotHttpError(e) && e.status === 404) {
|
|
85
100
|
uiLogger.error(commands.project.listBuilds.errors.projectNotFound(projectName));
|
|
86
101
|
}
|
|
@@ -90,6 +105,7 @@ async function handler(args) {
|
|
|
90
105
|
projectName,
|
|
91
106
|
}));
|
|
92
107
|
}
|
|
108
|
+
return exit(EXIT_CODES.ERROR);
|
|
93
109
|
}
|
|
94
110
|
return exit(EXIT_CODES.SUCCESS);
|
|
95
111
|
}
|
|
@@ -101,11 +117,19 @@ function projectListBuildsBuilder(yargs) {
|
|
|
101
117
|
},
|
|
102
118
|
limit: {
|
|
103
119
|
describe: commands.project.listBuilds.options.limit.describe,
|
|
104
|
-
type: '
|
|
120
|
+
type: 'number',
|
|
105
121
|
},
|
|
106
122
|
});
|
|
107
123
|
yargs.example([
|
|
108
124
|
['$0 project list-builds', commands.project.listBuilds.examples.default],
|
|
125
|
+
[
|
|
126
|
+
'$0 project list-builds --limit=5',
|
|
127
|
+
commands.project.listBuilds.examples.withLimit,
|
|
128
|
+
],
|
|
129
|
+
[
|
|
130
|
+
'$0 project list-builds --json',
|
|
131
|
+
commands.project.listBuilds.examples.json,
|
|
132
|
+
],
|
|
109
133
|
]);
|
|
110
134
|
return yargs;
|
|
111
135
|
}
|
|
@@ -114,11 +138,14 @@ const builder = makeYargsBuilder(projectListBuildsBuilder, command, describe, {
|
|
|
114
138
|
useConfigOptions: true,
|
|
115
139
|
useAccountOptions: true,
|
|
116
140
|
useEnvironmentOptions: true,
|
|
141
|
+
useJSONOutputOptions: true,
|
|
117
142
|
});
|
|
118
143
|
const projectListBuildsCommand = {
|
|
119
144
|
command,
|
|
120
145
|
describe,
|
|
121
|
-
handler: makeWrappedYargsHandler('project-list-builds', handler
|
|
146
|
+
handler: makeWrappedYargsHandler('project-list-builds', handler, {
|
|
147
|
+
jsonOutputSchema: ProjectBuildsListSchema,
|
|
148
|
+
}),
|
|
122
149
|
builder,
|
|
123
150
|
};
|
|
124
151
|
export default projectListBuildsCommand;
|