@hubspot/cli 8.0.11-experimental.2 → 8.0.12-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/bin/cli.js +4 -3
- package/commands/account/clean.js +2 -0
- package/commands/account/createOverride.js +3 -0
- package/commands/account/info.js +34 -16
- package/commands/account/link.d.ts +4 -0
- package/commands/account/link.js +89 -0
- package/commands/account/list.js +29 -71
- package/commands/account/remove.js +2 -0
- package/commands/account/removeOverride.js +3 -0
- package/commands/account/unlink.d.ts +4 -0
- package/commands/account/unlink.js +70 -0
- package/commands/account/use.js +71 -1
- package/commands/account.js +4 -0
- package/commands/project/appInstallStatus.d.ts +4 -0
- package/commands/project/appInstallStatus.js +132 -0
- package/commands/project/create.js +8 -0
- package/commands/project/dev/deprecatedFlow.js +20 -2
- package/commands/project/dev/index.js +6 -0
- package/commands/project/dev/unifiedFlow.js +20 -3
- package/commands/project/lint.js +20 -2
- package/commands/project/upload.d.ts +2 -0
- package/commands/project/upload.js +47 -3
- package/commands/project.js +2 -0
- package/lang/en.d.ts +122 -0
- package/lang/en.js +136 -8
- package/lib/app/migrate.js +2 -1
- package/lib/constants.d.ts +2 -0
- package/lib/constants.js +4 -0
- package/lib/doctor/Doctor.js +5 -5
- package/lib/link/accountTableUtils.d.ts +10 -0
- package/lib/link/accountTableUtils.js +39 -0
- package/lib/link/index.d.ts +18 -0
- package/lib/link/index.js +185 -0
- package/lib/link/linkUtils.d.ts +5 -0
- package/lib/link/linkUtils.js +49 -0
- package/lib/link/prompts.d.ts +7 -0
- package/lib/link/prompts.js +126 -0
- package/lib/link/renderLinkedAccountsTable.d.ts +2 -0
- package/lib/link/renderLinkedAccountsTable.js +14 -0
- package/lib/link/warnIfLinkedDirectory.d.ts +1 -0
- package/lib/link/warnIfLinkedDirectory.js +9 -0
- package/lib/projects/ProjectLogsManager.js +4 -1
- package/lib/projects/localDev/DevServerManager_DEPRECATED.d.ts +2 -1
- package/lib/projects/localDev/DevServerManager_DEPRECATED.js +2 -2
- package/lib/projects/localDev/LocalDevManager_DEPRECATED.d.ts +2 -0
- package/lib/projects/localDev/LocalDevManager_DEPRECATED.js +3 -0
- package/lib/projects/preview.d.ts +7 -0
- package/lib/projects/preview.js +58 -0
- package/lib/projects/uieLinting.d.ts +17 -3
- package/lib/projects/uieLinting.js +93 -28
- package/lib/projects/upload.d.ts +1 -0
- package/lib/projects/upload.js +4 -3
- package/lib/prompts/projectsLogsPrompt.js +3 -0
- package/lib/prompts/promptUtils.js +1 -0
- package/lib/ui/accountTable.d.ts +8 -0
- package/lib/ui/accountTable.js +67 -0
- package/lib/yargs/parseYargsOrExit.d.ts +4 -0
- package/lib/yargs/parseYargsOrExit.js +25 -0
- package/mcp-server/server.js +39 -1
- package/mcp-server/tools/index.js +2 -0
- package/mcp-server/tools/project/AddFeatureToProjectTool.js +1 -1
- package/mcp-server/tools/project/CreateTestAccountTool.js +1 -1
- package/mcp-server/tools/project/DeployProjectTool.js +1 -1
- package/mcp-server/tools/project/FindProjectsTool.d.ts +15 -0
- package/mcp-server/tools/project/FindProjectsTool.js +60 -0
- package/mcp-server/tools/project/GetBuildLogsTool.js +1 -1
- package/mcp-server/tools/project/GetBuildStatusTool.js +1 -1
- package/mcp-server/tools/project/UploadProjectTools.js +1 -1
- package/mcp-server/tools/project/ValidateProjectTool.js +1 -1
- package/package.json +7 -7
- package/types/Link.d.ts +32 -0
- package/types/Link.js +5 -0
- package/types/PackageJson.d.ts +1 -0
- package/types/Prompts.d.ts +1 -0
- package/types/Yargs.d.ts +1 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { fetchAppInstallationData } from '@hubspot/local-dev-lib/api/localDevAuth';
|
|
3
|
+
import { fetchProject } from '@hubspot/local-dev-lib/api/projects';
|
|
4
|
+
import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
|
|
5
|
+
import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
|
|
6
|
+
import { translateForLocalDev } from '@hubspot/project-parsing-lib/translate';
|
|
7
|
+
import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
|
|
8
|
+
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
9
|
+
import { uiLogger } from '../../lib/ui/logger.js';
|
|
10
|
+
import { ApiErrorContext, debugError, logError, } from '../../lib/errorHandlers/index.js';
|
|
11
|
+
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
12
|
+
import { commands } from '../../lang/en.js';
|
|
13
|
+
import { getProjectConfig } from '../../lib/projects/config.js';
|
|
14
|
+
import { isAppIRNode } from '../../lib/projects/structure.js';
|
|
15
|
+
import { APP_AUTH_TYPES } from '../../lib/constants.js';
|
|
16
|
+
const command = 'app-install-status';
|
|
17
|
+
const describe = commands.project.installStatus.describe;
|
|
18
|
+
async function handler(args) {
|
|
19
|
+
const { derivedAccountId, formatOutputAsJson, exit } = args;
|
|
20
|
+
const { projectConfig, projectDir } = await getProjectConfig();
|
|
21
|
+
if (!projectConfig || !projectDir) {
|
|
22
|
+
uiLogger.error(commands.project.installStatus.errors.noProjectConfig);
|
|
23
|
+
return exit(EXIT_CODES.ERROR);
|
|
24
|
+
}
|
|
25
|
+
if (isLegacyProject(projectConfig.platformVersion)) {
|
|
26
|
+
uiLogger.error(commands.project.installStatus.errors.unsupportedPlatformVersion(projectConfig.platformVersion));
|
|
27
|
+
return exit(EXIT_CODES.ERROR);
|
|
28
|
+
}
|
|
29
|
+
let appNode;
|
|
30
|
+
try {
|
|
31
|
+
const { intermediateNodesIndexedByUid } = await translateForLocalDev({
|
|
32
|
+
projectSourceDir: path.join(projectDir, projectConfig.srcDir),
|
|
33
|
+
platformVersion: projectConfig.platformVersion,
|
|
34
|
+
accountId: derivedAccountId,
|
|
35
|
+
}, { skipValidation: true });
|
|
36
|
+
appNode = Object.values(intermediateNodesIndexedByUid).find(isAppIRNode);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
debugError(error);
|
|
40
|
+
uiLogger.error(commands.project.installStatus.errors.failedToParseProject);
|
|
41
|
+
return exit(EXIT_CODES.ERROR);
|
|
42
|
+
}
|
|
43
|
+
if (!appNode) {
|
|
44
|
+
uiLogger.error(commands.project.installStatus.errors.noAppInProject);
|
|
45
|
+
return exit(EXIT_CODES.ERROR);
|
|
46
|
+
}
|
|
47
|
+
if (appNode.config.auth.type.toLowerCase() !== APP_AUTH_TYPES.STATIC) {
|
|
48
|
+
uiLogger.error(commands.project.installStatus.errors.unsupportedAuthType(appNode.config.auth.type));
|
|
49
|
+
return exit(EXIT_CODES.ERROR);
|
|
50
|
+
}
|
|
51
|
+
let projectId;
|
|
52
|
+
try {
|
|
53
|
+
const response = await fetchProject(derivedAccountId, projectConfig.name);
|
|
54
|
+
projectId = response.data.id;
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
logError(error, new ApiErrorContext({
|
|
58
|
+
accountId: derivedAccountId,
|
|
59
|
+
projectName: projectConfig.name,
|
|
60
|
+
}));
|
|
61
|
+
return exit(EXIT_CODES.ERROR);
|
|
62
|
+
}
|
|
63
|
+
let isInstalledWithScopeGroups = false;
|
|
64
|
+
let previouslyAuthorizedScopeGroups = [];
|
|
65
|
+
let appId;
|
|
66
|
+
try {
|
|
67
|
+
const response = await fetchAppInstallationData(derivedAccountId, projectId, appNode.uid, appNode.config.auth.requiredScopes, appNode.config.auth.optionalScopes);
|
|
68
|
+
isInstalledWithScopeGroups = response.data.isInstalledWithScopeGroups;
|
|
69
|
+
previouslyAuthorizedScopeGroups =
|
|
70
|
+
response.data.previouslyAuthorizedScopeGroups;
|
|
71
|
+
appId = response.data.appId;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
if (!isHubSpotHttpError(error) || error.status !== 404) {
|
|
75
|
+
logError(error, new ApiErrorContext({
|
|
76
|
+
accountId: derivedAccountId,
|
|
77
|
+
projectName: projectConfig.name,
|
|
78
|
+
}));
|
|
79
|
+
return exit(EXIT_CODES.ERROR);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const isInstalled = isInstalledWithScopeGroups || previouslyAuthorizedScopeGroups.length > 0;
|
|
83
|
+
if (formatOutputAsJson) {
|
|
84
|
+
uiLogger.json({
|
|
85
|
+
appId,
|
|
86
|
+
appUid: appNode.uid,
|
|
87
|
+
accountId: derivedAccountId,
|
|
88
|
+
projectId,
|
|
89
|
+
isInstalled,
|
|
90
|
+
isInstalledWithCurrentScopes: isInstalledWithScopeGroups,
|
|
91
|
+
previouslyAuthorizedScopeGroups,
|
|
92
|
+
});
|
|
93
|
+
return exit(isInstalled ? EXIT_CODES.SUCCESS : EXIT_CODES.WARNING);
|
|
94
|
+
}
|
|
95
|
+
if (isInstalled) {
|
|
96
|
+
if (isInstalledWithScopeGroups) {
|
|
97
|
+
uiLogger.success(commands.project.installStatus.success.installed(appNode.config.name, derivedAccountId));
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
uiLogger.success(commands.project.installStatus.success.installedWithOutdatedScopes(appNode.config.name, derivedAccountId));
|
|
101
|
+
}
|
|
102
|
+
return exit(EXIT_CODES.SUCCESS);
|
|
103
|
+
}
|
|
104
|
+
uiLogger.log(commands.project.installStatus.notInstalled(appNode.config.name, derivedAccountId));
|
|
105
|
+
return exit(EXIT_CODES.WARNING);
|
|
106
|
+
}
|
|
107
|
+
function projectInstallStatusBuilder(yargs) {
|
|
108
|
+
yargs.example([
|
|
109
|
+
[
|
|
110
|
+
'$0 project app-install-status',
|
|
111
|
+
commands.project.installStatus.examples.default,
|
|
112
|
+
],
|
|
113
|
+
[
|
|
114
|
+
'$0 project app-install-status --json',
|
|
115
|
+
commands.project.installStatus.examples.json,
|
|
116
|
+
],
|
|
117
|
+
]);
|
|
118
|
+
return yargs;
|
|
119
|
+
}
|
|
120
|
+
const builder = makeYargsBuilder(projectInstallStatusBuilder, command, describe, {
|
|
121
|
+
useGlobalOptions: true,
|
|
122
|
+
useConfigOptions: true,
|
|
123
|
+
useAccountOptions: true,
|
|
124
|
+
useJSONOutputOptions: true,
|
|
125
|
+
});
|
|
126
|
+
const projectInstallStatusCommand = {
|
|
127
|
+
command,
|
|
128
|
+
describe,
|
|
129
|
+
handler: makeYargsHandlerWithUsageTracking('project-app-install-status', handler),
|
|
130
|
+
builder,
|
|
131
|
+
};
|
|
132
|
+
export default projectInstallStatusCommand;
|
|
@@ -19,8 +19,15 @@ import { updateHsMetaFilesWithAutoGeneratedFields } from '../../lib/projects/com
|
|
|
19
19
|
import SpinniesManager from '../../lib/ui/SpinniesManager.js';
|
|
20
20
|
const command = ['create', 'init'];
|
|
21
21
|
const describe = commands.project.create.describe;
|
|
22
|
+
const BETA_VERSIONS = [
|
|
23
|
+
PLATFORM_VERSIONS.v2026_09_BETA,
|
|
24
|
+
PLATFORM_VERSIONS.v2026_03_BETA,
|
|
25
|
+
];
|
|
22
26
|
async function handler(args) {
|
|
23
27
|
const { platformVersion, templateSource, exit, addUsageMetadata } = args;
|
|
28
|
+
if (BETA_VERSIONS.includes(platformVersion)) {
|
|
29
|
+
uiLogger.warn(commands.project.create.warnings.betaPlatformVersion(platformVersion));
|
|
30
|
+
}
|
|
24
31
|
if (templateSource && !templateSource.includes('/')) {
|
|
25
32
|
uiLogger.error(commands.project.create.errors.invalidTemplateSource);
|
|
26
33
|
return exit(EXIT_CODES.ERROR);
|
|
@@ -128,6 +135,7 @@ function projectCreateBuilder(yargs) {
|
|
|
128
135
|
PLATFORM_VERSIONS.v2025_2,
|
|
129
136
|
PLATFORM_VERSIONS.v2026_03_BETA,
|
|
130
137
|
PLATFORM_VERSIONS.v2026_03,
|
|
138
|
+
PLATFORM_VERSIONS.v2026_09_BETA,
|
|
131
139
|
],
|
|
132
140
|
default: PLATFORM_VERSIONS.v2026_03,
|
|
133
141
|
},
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { getConfigAccountById,
|
|
1
|
+
import { getConfigAccountById, getLinkedOrAllConfigAccounts, getConfigAccountEnvironment, } from '@hubspot/local-dev-lib/config';
|
|
2
|
+
import { getHsSettingsFileIfExists, getHsSettingsFilePath, } from '@hubspot/local-dev-lib/config/hsSettings';
|
|
2
3
|
import { findProjectComponents, getProjectComponentTypes, } from '../../../lib/projects/structure.js';
|
|
3
4
|
import { ComponentTypes } from '../../../types/Projects.js';
|
|
4
5
|
import { commands } from '../../../lang/en.js';
|
|
@@ -11,6 +12,7 @@ import { handleExit } from '../../../lib/process.js';
|
|
|
11
12
|
import { getErrorMessage } from '../../../lib/errorHandlers/index.js';
|
|
12
13
|
import { isSandbox, isDeveloperTestAccount, } from '../../../lib/accountTypes.js';
|
|
13
14
|
import { ensureProjectExists } from '../../../lib/projects/ensureProjectExists.js';
|
|
15
|
+
import { isDirectoryLinked, addAccountToLinkedSettings, } from '../../../lib/link/linkUtils.js';
|
|
14
16
|
export async function deprecatedProjectDevFlow({ args, accountId, projectConfig, projectDir, }) {
|
|
15
17
|
const { userProvidedAccount, derivedAccountId, exit } = args;
|
|
16
18
|
const env = getConfigAccountEnvironment(derivedAccountId);
|
|
@@ -32,7 +34,9 @@ export async function deprecatedProjectDevFlow({ args, accountId, projectConfig,
|
|
|
32
34
|
uiLogger.error(commands.project.dev.errors.invalidProjectComponents);
|
|
33
35
|
return exit(EXIT_CODES.SUCCESS);
|
|
34
36
|
}
|
|
35
|
-
const
|
|
37
|
+
const hsSettings = getHsSettingsFileIfExists();
|
|
38
|
+
const directoryIsLinked = isDirectoryLinked(hsSettings);
|
|
39
|
+
const accounts = getLinkedOrAllConfigAccounts();
|
|
36
40
|
if (!accounts) {
|
|
37
41
|
uiLogger.error(commands.project.dev.errors.noAccountsInConfig);
|
|
38
42
|
return exit(EXIT_CODES.ERROR);
|
|
@@ -69,6 +73,10 @@ export async function deprecatedProjectDevFlow({ args, accountId, projectConfig,
|
|
|
69
73
|
else {
|
|
70
74
|
await checkIfDefaultAccountIsSupported(accountConfig, hasPublicApps, exit);
|
|
71
75
|
}
|
|
76
|
+
if (directoryIsLinked) {
|
|
77
|
+
uiLogger.log('');
|
|
78
|
+
uiLogger.info(commands.account.subcommands.link.shared.usingLinkedAccounts(getHsSettingsFilePath()));
|
|
79
|
+
}
|
|
72
80
|
// The user is targeting an account type that we recommend developing on
|
|
73
81
|
if (!targetProjectAccountId && bypassRecommendedAccountPrompt) {
|
|
74
82
|
targetTestingAccountId = derivedAccountId;
|
|
@@ -101,6 +109,9 @@ export async function deprecatedProjectDevFlow({ args, accountId, projectConfig,
|
|
|
101
109
|
if (!accountAdded) {
|
|
102
110
|
return exit(EXIT_CODES.SUCCESS);
|
|
103
111
|
}
|
|
112
|
+
if (directoryIsLinked) {
|
|
113
|
+
addAccountToLinkedSettings(notInConfigAccount.id);
|
|
114
|
+
}
|
|
104
115
|
}
|
|
105
116
|
createNewSandbox = hasPrivateApps && createNestedAccount;
|
|
106
117
|
createNewDeveloperTestAccount = hasPublicApps && createNestedAccount;
|
|
@@ -114,6 +125,9 @@ export async function deprecatedProjectDevFlow({ args, accountId, projectConfig,
|
|
|
114
125
|
}
|
|
115
126
|
// We will be running our tests against this new sandbox account
|
|
116
127
|
targetTestingAccountId = targetProjectAccountId;
|
|
128
|
+
if (directoryIsLinked) {
|
|
129
|
+
addAccountToLinkedSettings(targetProjectAccountId);
|
|
130
|
+
}
|
|
117
131
|
}
|
|
118
132
|
if (createNewDeveloperTestAccount) {
|
|
119
133
|
try {
|
|
@@ -123,6 +137,9 @@ export async function deprecatedProjectDevFlow({ args, accountId, projectConfig,
|
|
|
123
137
|
return exit(EXIT_CODES.ERROR);
|
|
124
138
|
}
|
|
125
139
|
targetProjectAccountId = derivedAccountId;
|
|
140
|
+
if (directoryIsLinked) {
|
|
141
|
+
addAccountToLinkedSettings(targetTestingAccountId);
|
|
142
|
+
}
|
|
126
143
|
}
|
|
127
144
|
if (!targetProjectAccountId || !targetTestingAccountId) {
|
|
128
145
|
uiLogger.error(commands.project.dev.errors.noAccount(accountId));
|
|
@@ -156,6 +173,7 @@ export async function deprecatedProjectDevFlow({ args, accountId, projectConfig,
|
|
|
156
173
|
targetAccountId: targetTestingAccountId,
|
|
157
174
|
env,
|
|
158
175
|
exit,
|
|
176
|
+
port: args.port,
|
|
159
177
|
});
|
|
160
178
|
await LocalDev.start();
|
|
161
179
|
handleExit(({ isSIGHUP }) => LocalDev.stop(!isSIGHUP));
|
|
@@ -13,6 +13,7 @@ import { uiLogger } from '../../../lib/ui/logger.js';
|
|
|
13
13
|
import { logError } from '../../../lib/errorHandlers/index.js';
|
|
14
14
|
import { projectProfilePrompt } from '../../../lib/prompts/projectProfilePrompt.js';
|
|
15
15
|
import { isPromptExitError } from '../../../lib/errors/PromptExitError.js';
|
|
16
|
+
import { LOCAL_DEV_DEFAULT_PORT } from '../../../lib/constants.js';
|
|
16
17
|
const command = 'dev';
|
|
17
18
|
const describe = commands.project.dev.describe;
|
|
18
19
|
function validateAccountFlags(testingAccount, projectAccount, userProvidedAccount, useV2) {
|
|
@@ -149,6 +150,11 @@ function projectDevBuilder(yargs) {
|
|
|
149
150
|
type: 'string',
|
|
150
151
|
description: commands.project.dev.options.account,
|
|
151
152
|
});
|
|
153
|
+
yargs.option('port', {
|
|
154
|
+
type: 'number',
|
|
155
|
+
description: commands.project.dev.options.port,
|
|
156
|
+
default: LOCAL_DEV_DEFAULT_PORT,
|
|
157
|
+
});
|
|
152
158
|
yargs.example([['$0 project dev', commands.project.dev.examples.default]]);
|
|
153
159
|
yargs.conflicts('profile', 'account');
|
|
154
160
|
yargs.conflicts('profile', 'testing-account');
|
|
@@ -3,7 +3,7 @@ import util from 'util';
|
|
|
3
3
|
import { HUBSPOT_ACCOUNT_TYPES } from '@hubspot/local-dev-lib/constants/config';
|
|
4
4
|
import { startPortManagerServer, stopPortManagerServer, } from '@hubspot/local-dev-lib/portManager';
|
|
5
5
|
import { isTranslationError, translateForLocalDev, } from '@hubspot/project-parsing-lib/translate';
|
|
6
|
-
import { getConfigAccountEnvironment,
|
|
6
|
+
import { getConfigAccountEnvironment, getLinkedOrAllConfigAccounts, getConfigAccountById, } from '@hubspot/local-dev-lib/config';
|
|
7
7
|
import { logError } from '../../../lib/errorHandlers/index.js';
|
|
8
8
|
import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
|
|
9
9
|
import { ensureProjectExists } from '../../../lib/projects/ensureProjectExists.js';
|
|
@@ -18,6 +18,8 @@ import { uiLogger } from '../../../lib/ui/logger.js';
|
|
|
18
18
|
import { commands } from '../../../lang/en.js';
|
|
19
19
|
import LocalDevWebsocketServer from '../../../lib/projects/localDev/LocalDevWebsocketServer.js';
|
|
20
20
|
import { isLocalDevRunning } from '../../../lib/projects/localDev/helpers/process.js';
|
|
21
|
+
import { getHsSettingsFileIfExists, getHsSettingsFilePath, } from '@hubspot/local-dev-lib/config/hsSettings';
|
|
22
|
+
import { isDirectoryLinked, addAccountToLinkedSettings, } from '../../../lib/link/linkUtils.js';
|
|
21
23
|
export async function unifiedProjectDevFlow({ args, targetProjectAccountId, providedTargetTestingAccountId, projectConfig, projectDir, }) {
|
|
22
24
|
const { exit } = args;
|
|
23
25
|
if (await isLocalDevRunning()) {
|
|
@@ -56,13 +58,19 @@ export async function unifiedProjectDevFlow({ args, targetProjectAccountId, prov
|
|
|
56
58
|
uiLogger.error(commands.project.dev.errors.noAccount(targetProjectAccountId));
|
|
57
59
|
return exit(EXIT_CODES.ERROR);
|
|
58
60
|
}
|
|
59
|
-
const
|
|
61
|
+
const hsSettings = getHsSettingsFileIfExists();
|
|
62
|
+
const directoryIsLinked = isDirectoryLinked(hsSettings);
|
|
63
|
+
const accounts = getLinkedOrAllConfigAccounts();
|
|
60
64
|
const accountIsCombined = await isUnifiedAccount(targetProjectAccountConfig);
|
|
61
65
|
const targetProjectAccountIsTestAccountOrSandbox = isTestAccountOrSandbox(targetProjectAccountConfig);
|
|
62
66
|
if (!accountIsCombined) {
|
|
63
67
|
uiLogger.error(commands.project.dev.errors.accountNotCombined);
|
|
64
68
|
return exit(EXIT_CODES.ERROR);
|
|
65
69
|
}
|
|
70
|
+
if (directoryIsLinked && !providedTargetTestingAccountId) {
|
|
71
|
+
uiLogger.log('');
|
|
72
|
+
uiLogger.info(commands.account.subcommands.link.shared.usingLinkedAccounts(getHsSettingsFilePath()));
|
|
73
|
+
}
|
|
66
74
|
let targetTestingAccountId = providedTargetTestingAccountId;
|
|
67
75
|
// Temporarily removing logic to use profile account as testing account
|
|
68
76
|
// if (profileConfig) {
|
|
@@ -90,6 +98,9 @@ export async function unifiedProjectDevFlow({ args, targetProjectAccountId, prov
|
|
|
90
98
|
if (!accountAdded) {
|
|
91
99
|
return exit(EXIT_CODES.SUCCESS);
|
|
92
100
|
}
|
|
101
|
+
if (directoryIsLinked) {
|
|
102
|
+
addAccountToLinkedSettings(devAccountPromptResponse.notInConfigAccount.id);
|
|
103
|
+
}
|
|
93
104
|
}
|
|
94
105
|
else if (devAccountPromptResponse.createNestedAccount) {
|
|
95
106
|
// Create a new developer test account and automatically add it to the CLI config
|
|
@@ -99,6 +110,9 @@ export async function unifiedProjectDevFlow({ args, targetProjectAccountId, prov
|
|
|
99
110
|
catch {
|
|
100
111
|
return exit(EXIT_CODES.ERROR);
|
|
101
112
|
}
|
|
113
|
+
if (directoryIsLinked) {
|
|
114
|
+
addAccountToLinkedSettings(targetTestingAccountId);
|
|
115
|
+
}
|
|
102
116
|
}
|
|
103
117
|
}
|
|
104
118
|
else if (accountType === HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX) {
|
|
@@ -112,6 +126,9 @@ export async function unifiedProjectDevFlow({ args, targetProjectAccountId, prov
|
|
|
112
126
|
catch {
|
|
113
127
|
return exit(EXIT_CODES.ERROR);
|
|
114
128
|
}
|
|
129
|
+
if (directoryIsLinked) {
|
|
130
|
+
addAccountToLinkedSettings(targetTestingAccountId);
|
|
131
|
+
}
|
|
115
132
|
}
|
|
116
133
|
}
|
|
117
134
|
else {
|
|
@@ -143,7 +160,7 @@ export async function unifiedProjectDevFlow({ args, targetProjectAccountId, prov
|
|
|
143
160
|
}
|
|
144
161
|
// End setup, start local dev process
|
|
145
162
|
try {
|
|
146
|
-
await startPortManagerServer();
|
|
163
|
+
await startPortManagerServer(args.port);
|
|
147
164
|
}
|
|
148
165
|
catch (e) {
|
|
149
166
|
logError(e);
|
package/commands/project/lint.js
CHANGED
|
@@ -10,7 +10,7 @@ import { logError } from '../../lib/errorHandlers/index.js';
|
|
|
10
10
|
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
11
11
|
import { promptUser } from '../../lib/prompts/promptUtils.js';
|
|
12
12
|
import SpinniesManager from '../../lib/ui/SpinniesManager.js';
|
|
13
|
-
import { areAllLintPackagesInstalled, getMissingLintPackages, lintPackages, displayLintResults, hasEslintConfig, hasDeprecatedEslintConfig, getDeprecatedEslintConfigFiles, createEslintConfig, REQUIRED_PACKAGES_AND_MIN_VERSIONS, } from '../../lib/projects/uieLinting.js';
|
|
13
|
+
import { areAllLintPackagesInstalled, getMissingLintPackages, getMissingLintScripts, addLintScriptsToPackageJson, lintPackages, displayLintResults, hasEslintConfig, hasDeprecatedEslintConfig, getDeprecatedEslintConfigFiles, createEslintConfig, REQUIRED_PACKAGES_AND_MIN_VERSIONS, } from '../../lib/projects/uieLinting.js';
|
|
14
14
|
const command = 'lint';
|
|
15
15
|
const describe = commands.project.lint.help.describe;
|
|
16
16
|
async function handler(args) {
|
|
@@ -117,9 +117,10 @@ async function handler(args) {
|
|
|
117
117
|
SpinniesManager.add('lintConfigCreate', {
|
|
118
118
|
text: commands.project.lint.loading.creatingConfig,
|
|
119
119
|
});
|
|
120
|
+
const platformVersion = projectConfig.projectConfig?.platformVersion ?? null;
|
|
120
121
|
const createdConfigs = [];
|
|
121
122
|
for (const location of locationsNeedingConfig) {
|
|
122
|
-
const configPath = createEslintConfig(location);
|
|
123
|
+
const configPath = await createEslintConfig(location, platformVersion);
|
|
123
124
|
createdConfigs.push(configPath);
|
|
124
125
|
}
|
|
125
126
|
SpinniesManager.succeed('lintConfigCreate');
|
|
@@ -132,6 +133,23 @@ async function handler(args) {
|
|
|
132
133
|
return exit(EXIT_CODES.ERROR);
|
|
133
134
|
}
|
|
134
135
|
}
|
|
136
|
+
const locationsNeedingScripts = locationsReadyToLint.filter(location => getMissingLintScripts(location).length > 0);
|
|
137
|
+
if (locationsNeedingScripts.length > 0) {
|
|
138
|
+
SpinniesManager.add('lintScriptsAdd', {
|
|
139
|
+
text: commands.project.lint.loading.addingLintScripts,
|
|
140
|
+
});
|
|
141
|
+
const addedResults = [];
|
|
142
|
+
for (const location of locationsNeedingScripts) {
|
|
143
|
+
const result = addLintScriptsToPackageJson(location);
|
|
144
|
+
if (result.added.length > 0) {
|
|
145
|
+
addedResults.push(result);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
SpinniesManager.succeed('lintScriptsAdd');
|
|
149
|
+
addedResults.forEach(({ added, relativePath }) => {
|
|
150
|
+
uiLogger.success(commands.project.lint.lintScriptsAdded(added, relativePath));
|
|
151
|
+
});
|
|
152
|
+
}
|
|
135
153
|
SpinniesManager.add('lintRun', {
|
|
136
154
|
text: commands.project.lint.loading.linting,
|
|
137
155
|
});
|
|
@@ -5,6 +5,8 @@ export type ProjectUploadArgs = CommonArgs & JSONOutputArgs & {
|
|
|
5
5
|
m: string;
|
|
6
6
|
skipValidation: boolean;
|
|
7
7
|
profile?: string;
|
|
8
|
+
preview: boolean;
|
|
9
|
+
target?: number;
|
|
8
10
|
};
|
|
9
11
|
declare const projectUploadCommand: YargsCommandModule<unknown, ProjectUploadArgs>;
|
|
10
12
|
export default projectUploadCommand;
|
|
@@ -8,7 +8,8 @@ import { logFeedbackMessage } from '../../lib/projects/ui.js';
|
|
|
8
8
|
import { handleProjectUpload } from '../../lib/projects/upload.js';
|
|
9
9
|
import { loadAndValidateProfile } from '../../lib/projects/projectProfiles.js';
|
|
10
10
|
import { displayWarnLogs, pollProjectBuildAndDeploy, } from '../../lib/projects/pollProjectBuildAndDeploy.js';
|
|
11
|
-
import {
|
|
11
|
+
import { triggerAndPollPreview } from '../../lib/projects/preview.js';
|
|
12
|
+
import { commands, lib } from '../../lang/en.js';
|
|
12
13
|
import { PROJECT_ERROR_TYPES } from '../../lib/constants.js';
|
|
13
14
|
import { logError, ApiErrorContext } from '../../lib/errorHandlers/index.js';
|
|
14
15
|
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
@@ -17,8 +18,22 @@ import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
|
17
18
|
import { projectProfilePrompt } from '../../lib/prompts/projectProfilePrompt.js';
|
|
18
19
|
const command = 'upload';
|
|
19
20
|
const describe = commands.project.upload.describe;
|
|
21
|
+
async function handlePreview(accountId, projectId, buildId, targetPortalId) {
|
|
22
|
+
if (!projectId) {
|
|
23
|
+
uiLogger.warn(lib.projectPreview.missingProjectId);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const previewResult = await triggerAndPollPreview(accountId, projectId, buildId, targetPortalId);
|
|
27
|
+
if (!previewResult.succeeded) {
|
|
28
|
+
uiLogger.warn(lib.projectPreview.warning);
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
releaseTag: previewResult.releaseTag,
|
|
32
|
+
succeeded: previewResult.succeeded,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
20
35
|
async function handler(args) {
|
|
21
|
-
const { forceCreate, message, derivedAccountId, skipValidation, formatOutputAsJson, profile: profileOption, useEnv: useEnvOption, exit, addUsageMetadata, } = args;
|
|
36
|
+
const { forceCreate, message, derivedAccountId, skipValidation, formatOutputAsJson, profile: profileOption, useEnv: useEnvOption, preview, target: targetPortalId, exit, addUsageMetadata, } = args;
|
|
22
37
|
const jsonOutput = {};
|
|
23
38
|
const { projectConfig, projectDir } = await getProjectConfig();
|
|
24
39
|
try {
|
|
@@ -56,7 +71,7 @@ async function handler(args) {
|
|
|
56
71
|
assetType: projectConfig.platformVersion,
|
|
57
72
|
});
|
|
58
73
|
try {
|
|
59
|
-
const { result, uploadError } = await handleProjectUpload({
|
|
74
|
+
const { result, uploadError, projectId } = await handleProjectUpload({
|
|
60
75
|
accountId: targetAccountId,
|
|
61
76
|
projectConfig,
|
|
62
77
|
projectDir,
|
|
@@ -90,6 +105,12 @@ async function handler(args) {
|
|
|
90
105
|
logFeedbackMessage(result.buildId);
|
|
91
106
|
await displayWarnLogs(targetAccountId, projectConfig.name, result.buildId);
|
|
92
107
|
}
|
|
108
|
+
if (result && result.succeeded && preview && targetPortalId) {
|
|
109
|
+
const previewJson = await handlePreview(targetAccountId, projectId, result.buildId, targetPortalId);
|
|
110
|
+
if (previewJson && formatOutputAsJson) {
|
|
111
|
+
jsonOutput.preview = previewJson;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
93
114
|
if (result && result.succeeded && formatOutputAsJson) {
|
|
94
115
|
jsonOutput.buildId = result.buildId;
|
|
95
116
|
if (result.deployResult) {
|
|
@@ -132,6 +153,25 @@ function projectUploadBuilder(yargs) {
|
|
|
132
153
|
alias: 'p',
|
|
133
154
|
describe: commands.project.upload.options.profile.describe,
|
|
134
155
|
},
|
|
156
|
+
preview: {
|
|
157
|
+
describe: commands.project.upload.options.preview.describe,
|
|
158
|
+
type: 'boolean',
|
|
159
|
+
default: false,
|
|
160
|
+
},
|
|
161
|
+
target: {
|
|
162
|
+
describe: commands.project.upload.options.target.describe,
|
|
163
|
+
type: 'number',
|
|
164
|
+
requiresArg: true,
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
yargs.check(argv => {
|
|
168
|
+
if (argv.preview && argv.target == null) {
|
|
169
|
+
throw new Error(commands.project.upload.errors.previewRequiresTarget);
|
|
170
|
+
}
|
|
171
|
+
if (argv.target != null && !argv.preview) {
|
|
172
|
+
throw new Error(commands.project.upload.errors.targetRequiresPreview);
|
|
173
|
+
}
|
|
174
|
+
return true;
|
|
135
175
|
});
|
|
136
176
|
yargs.conflicts('profile', 'account');
|
|
137
177
|
yargs.example([
|
|
@@ -140,6 +180,10 @@ function projectUploadBuilder(yargs) {
|
|
|
140
180
|
'$0 project upload --profile=profileName',
|
|
141
181
|
commands.project.upload.examples.withProfile,
|
|
142
182
|
],
|
|
183
|
+
[
|
|
184
|
+
'$0 project upload --preview --target=12345',
|
|
185
|
+
commands.project.upload.examples.withPreview,
|
|
186
|
+
],
|
|
143
187
|
]);
|
|
144
188
|
return yargs;
|
|
145
189
|
}
|
package/commands/project.js
CHANGED
|
@@ -19,6 +19,7 @@ import projectValidate from './project/validate.js';
|
|
|
19
19
|
import list from './project/list.js';
|
|
20
20
|
import info from './project/info.js';
|
|
21
21
|
import deleteProject from './project/delete.js';
|
|
22
|
+
import appInstallStatus from './project/appInstallStatus.js';
|
|
22
23
|
import { makeYargsBuilder } from '../lib/yargsUtils.js';
|
|
23
24
|
import { getProjectConfig } from '../lib/projects/config.js';
|
|
24
25
|
import { isSupportedPlatformVersion, LATEST_SUPPORTED_PLATFORM_VERSION, } from '@hubspot/project-parsing-lib/projects';
|
|
@@ -66,6 +67,7 @@ function projectBuilder(yargs) {
|
|
|
66
67
|
.command(updateDeps)
|
|
67
68
|
.command(profile)
|
|
68
69
|
.command(projectValidate)
|
|
70
|
+
.command(appInstallStatus)
|
|
69
71
|
.demandCommand(1, '');
|
|
70
72
|
return yargs;
|
|
71
73
|
}
|