@hubspot/cli 7.7.16-experimental.0 → 7.7.16-experimental.2
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 -0
- package/bin/hs +1 -1
- package/commands/getStarted.d.ts +9 -0
- package/commands/getStarted.js +227 -0
- package/commands/init.js +6 -1
- package/commands/mcp/setup.d.ts +2 -2
- package/commands/mcp/setup.js +2 -0
- package/commands/mcp/start.d.ts +2 -2
- package/commands/mcp/start.js +3 -1
- package/commands/project/deploy.d.ts +1 -0
- package/commands/project/deploy.js +29 -3
- package/commands/project/upload.d.ts +2 -2
- package/commands/project/upload.js +18 -23
- package/commands/project/validate.d.ts +6 -0
- package/commands/project/validate.js +82 -0
- package/commands/project.js +2 -0
- package/commands/testAccount/create.d.ts +6 -0
- package/commands/testAccount/create.js +110 -0
- package/commands/testAccount/createConfig.d.ts +10 -0
- package/commands/testAccount/createConfig.js +98 -0
- package/commands/testAccount/delete.d.ts +6 -0
- package/commands/testAccount/delete.js +48 -0
- package/commands/testAccount.d.ts +3 -0
- package/commands/testAccount.js +28 -0
- package/lang/en.d.ts +143 -29
- package/lang/en.js +143 -32
- package/lang/en.lyaml +9 -14
- package/lib/app/migrate.js +15 -3
- package/lib/commonOpts.d.ts +2 -0
- package/lib/commonOpts.js +21 -9
- package/lib/constants.d.ts +5 -0
- package/lib/constants.js +6 -1
- package/lib/doctor/Doctor.js +1 -1
- package/lib/errorHandlers/index.js +7 -0
- package/lib/mcp/setup.d.ts +9 -0
- package/lib/mcp/setup.js +23 -21
- package/lib/projectProfiles.d.ts +1 -0
- package/lib/projectProfiles.js +18 -0
- package/lib/projects/buildAndDeploy.js +1 -1
- package/lib/projects/localDev/AppDevModeInterface.d.ts +3 -0
- package/lib/projects/localDev/AppDevModeInterface.js +45 -16
- package/lib/projects/localDev/LocalDevManager.js +1 -1
- package/lib/projects/upload.d.ts +3 -0
- package/lib/projects/upload.js +56 -22
- package/lib/projects/urls.d.ts +2 -0
- package/lib/projects/urls.js +10 -0
- package/lib/prompts/createDeveloperTestAccountConfigPrompt.d.ts +17 -0
- package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +96 -0
- package/lib/prompts/installAppPrompt.d.ts +2 -1
- package/lib/prompts/installAppPrompt.js +12 -2
- package/lib/prompts/promptUtils.d.ts +1 -0
- package/lib/prompts/promptUtils.js +2 -0
- package/lib/ui/logger.d.ts +1 -0
- package/lib/ui/logger.js +1 -0
- package/lib/yargsUtils.d.ts +1 -0
- package/lib/yargsUtils.js +3 -0
- package/mcp-server/tools/index.js +2 -0
- package/mcp-server/tools/project/CreateProjectTool.d.ts +3 -3
- package/mcp-server/tools/project/CreateProjectTool.js +5 -1
- package/mcp-server/tools/project/DeployProject.js +1 -1
- package/mcp-server/tools/project/UploadProjectTools.js +1 -1
- package/mcp-server/tools/project/ValidateProjectTool.d.ts +17 -0
- package/mcp-server/tools/project/ValidateProjectTool.js +35 -0
- package/package.json +10 -9
- package/types/LocalDev.d.ts +1 -0
- package/types/Yargs.d.ts +4 -0
package/lib/mcp/setup.js
CHANGED
|
@@ -5,17 +5,22 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.supportedTools = void 0;
|
|
7
7
|
exports.addMintlifyMcpServer = addMintlifyMcpServer;
|
|
8
|
+
exports.setupMintlify = setupMintlify;
|
|
8
9
|
exports.addMcpServerToConfig = addMcpServerToConfig;
|
|
10
|
+
exports.setupClaudeCode = setupClaudeCode;
|
|
11
|
+
exports.setupCursor = setupCursor;
|
|
12
|
+
exports.setupWindsurf = setupWindsurf;
|
|
9
13
|
const logger_1 = require("../ui/logger");
|
|
10
14
|
const en_1 = require("../../lang/en");
|
|
11
|
-
const child_process_1 = require("child_process");
|
|
12
15
|
const promptUtils_1 = require("../prompts/promptUtils");
|
|
13
16
|
const SpinniesManager_1 = __importDefault(require("../ui/SpinniesManager"));
|
|
14
17
|
const errorHandlers_1 = require("../errorHandlers");
|
|
15
|
-
const fs_1 = __importDefault(require("fs"));
|
|
16
18
|
const command_1 = require("../../mcp-server/utils/command");
|
|
19
|
+
const child_process_1 = require("child_process");
|
|
17
20
|
const path_1 = __importDefault(require("path"));
|
|
18
21
|
const os_1 = __importDefault(require("os"));
|
|
22
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
23
|
+
const fs_1 = require("fs");
|
|
19
24
|
const mcpServerName = 'hubspot-cli-mcp';
|
|
20
25
|
const claudeCode = 'claude';
|
|
21
26
|
const windsurf = 'windsurf';
|
|
@@ -26,12 +31,14 @@ exports.supportedTools = [
|
|
|
26
31
|
{ name: en_1.commands.mcp.setup.cursor, value: cursor },
|
|
27
32
|
{ name: en_1.commands.mcp.setup.windsurf, value: windsurf },
|
|
28
33
|
];
|
|
29
|
-
const
|
|
30
|
-
|
|
34
|
+
const defaultMcpCommand = {
|
|
35
|
+
command: 'hs',
|
|
36
|
+
args: ['mcp', 'start'],
|
|
37
|
+
};
|
|
31
38
|
async function addMintlifyMcpServer(installTargets) {
|
|
32
39
|
await runSetupFunction(() => setupMintlify(installTargets));
|
|
33
40
|
}
|
|
34
|
-
async function setupMintlify(derivedTargets) {
|
|
41
|
+
async function setupMintlify(derivedTargets = supportedMintlifyClients) {
|
|
35
42
|
logger_1.uiLogger.info(en_1.commands.mcp.setup.installingDocSearch);
|
|
36
43
|
logger_1.uiLogger.log('');
|
|
37
44
|
return new Promise(resolve => {
|
|
@@ -101,15 +108,12 @@ function setupMcpConfigFile(config) {
|
|
|
101
108
|
SpinniesManager_1.default.add('spinner', {
|
|
102
109
|
text: config.configuringMessage,
|
|
103
110
|
});
|
|
104
|
-
if (!fs_1.
|
|
105
|
-
|
|
106
|
-
text: config.configMissingMessage,
|
|
107
|
-
});
|
|
108
|
-
return false;
|
|
111
|
+
if (!(0, fs_1.existsSync)(config.configPath)) {
|
|
112
|
+
fs_extra_1.default.writeFileSync(config.configPath, JSON.stringify({}, null, 2));
|
|
109
113
|
}
|
|
110
114
|
let mcpConfig = {};
|
|
111
115
|
try {
|
|
112
|
-
const configContent =
|
|
116
|
+
const configContent = fs_extra_1.default.readFileSync(config.configPath, 'utf8');
|
|
113
117
|
mcpConfig = JSON.parse(configContent);
|
|
114
118
|
}
|
|
115
119
|
catch (error) {
|
|
@@ -125,11 +129,10 @@ function setupMcpConfigFile(config) {
|
|
|
125
129
|
}
|
|
126
130
|
// Add or update HubSpot CLI MCP server
|
|
127
131
|
mcpConfig.mcpServers[mcpServerName] = {
|
|
128
|
-
|
|
129
|
-
args: mcpCommandArgs,
|
|
132
|
+
...config.mcpCommand,
|
|
130
133
|
};
|
|
131
134
|
// Write the updated config
|
|
132
|
-
|
|
135
|
+
fs_extra_1.default.writeFileSync(config.configPath, JSON.stringify(mcpConfig, null, 2));
|
|
133
136
|
SpinniesManager_1.default.succeed('spinner', {
|
|
134
137
|
text: config.configuredMessage,
|
|
135
138
|
});
|
|
@@ -143,7 +146,7 @@ function setupMcpConfigFile(config) {
|
|
|
143
146
|
return false;
|
|
144
147
|
}
|
|
145
148
|
}
|
|
146
|
-
async function setupClaudeCode() {
|
|
149
|
+
async function setupClaudeCode(mcpCommand = defaultMcpCommand) {
|
|
147
150
|
try {
|
|
148
151
|
SpinniesManager_1.default.add('claudeCode', {
|
|
149
152
|
text: en_1.commands.mcp.setup.spinners.configuringClaudeCode,
|
|
@@ -154,8 +157,7 @@ async function setupClaudeCode() {
|
|
|
154
157
|
// Run claude mcp add command
|
|
155
158
|
const mcpConfig = JSON.stringify({
|
|
156
159
|
type: 'stdio',
|
|
157
|
-
|
|
158
|
-
args: mcpCommandArgs,
|
|
160
|
+
...mcpCommand,
|
|
159
161
|
});
|
|
160
162
|
const { stdout } = await (0, command_1.execAsync)('claude mcp list');
|
|
161
163
|
if (stdout.includes(mcpServerName)) {
|
|
@@ -194,23 +196,23 @@ async function setupClaudeCode() {
|
|
|
194
196
|
return false;
|
|
195
197
|
}
|
|
196
198
|
}
|
|
197
|
-
function setupCursor() {
|
|
199
|
+
function setupCursor(mcpCommand = defaultMcpCommand) {
|
|
198
200
|
const cursorConfigPath = path_1.default.join(os_1.default.homedir(), '.cursor', 'mcp.json');
|
|
199
201
|
return setupMcpConfigFile({
|
|
200
202
|
configPath: cursorConfigPath,
|
|
201
203
|
configuringMessage: en_1.commands.mcp.setup.spinners.configuringCursor,
|
|
202
204
|
configuredMessage: en_1.commands.mcp.setup.spinners.configuredCursor,
|
|
203
205
|
failedMessage: en_1.commands.mcp.setup.spinners.failedToConfigureCursor,
|
|
204
|
-
|
|
206
|
+
mcpCommand,
|
|
205
207
|
});
|
|
206
208
|
}
|
|
207
|
-
function setupWindsurf() {
|
|
209
|
+
function setupWindsurf(mcpCommand = defaultMcpCommand) {
|
|
208
210
|
const windsurfConfigPath = path_1.default.join(os_1.default.homedir(), '.codeium', 'windsurf', 'mcp_config.json');
|
|
209
211
|
return setupMcpConfigFile({
|
|
210
212
|
configPath: windsurfConfigPath,
|
|
211
213
|
configuringMessage: en_1.commands.mcp.setup.spinners.configuringWindsurf,
|
|
212
214
|
configuredMessage: en_1.commands.mcp.setup.spinners.configuredWindsurf,
|
|
213
215
|
failedMessage: en_1.commands.mcp.setup.spinners.failedToConfigureWindsurf,
|
|
214
|
-
|
|
216
|
+
mcpCommand,
|
|
215
217
|
});
|
|
216
218
|
}
|
package/lib/projectProfiles.d.ts
CHANGED
|
@@ -4,3 +4,4 @@ export declare function logProfileHeader(profileName: string): void;
|
|
|
4
4
|
export declare function logProfileFooter(profile: HsProfileFile, includeVariables?: boolean): void;
|
|
5
5
|
export declare function loadProfile(projectConfig: ProjectConfig | null, projectDir: string | null, profileName: string): HsProfileFile | undefined;
|
|
6
6
|
export declare function exitIfUsingProfiles(projectConfig: ProjectConfig | null, projectDir: string | null): Promise<void>;
|
|
7
|
+
export declare function loadAndValidateProfile(projectConfig: ProjectConfig | null, projectDir: string | null, argsProfile: string | undefined): Promise<number | undefined>;
|
package/lib/projectProfiles.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.logProfileHeader = logProfileHeader;
|
|
|
7
7
|
exports.logProfileFooter = logProfileFooter;
|
|
8
8
|
exports.loadProfile = loadProfile;
|
|
9
9
|
exports.exitIfUsingProfiles = exitIfUsingProfiles;
|
|
10
|
+
exports.loadAndValidateProfile = loadAndValidateProfile;
|
|
10
11
|
const path_1 = __importDefault(require("path"));
|
|
11
12
|
const project_parsing_lib_1 = require("@hubspot/project-parsing-lib");
|
|
12
13
|
const en_1 = require("../lang/en");
|
|
@@ -63,3 +64,20 @@ async function exitIfUsingProfiles(projectConfig, projectDir) {
|
|
|
63
64
|
}
|
|
64
65
|
}
|
|
65
66
|
}
|
|
67
|
+
async function loadAndValidateProfile(projectConfig, projectDir, argsProfile) {
|
|
68
|
+
if (argsProfile) {
|
|
69
|
+
logProfileHeader(argsProfile);
|
|
70
|
+
const profile = loadProfile(projectConfig, projectDir, argsProfile);
|
|
71
|
+
if (!profile) {
|
|
72
|
+
(0, ui_1.uiLine)();
|
|
73
|
+
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
74
|
+
}
|
|
75
|
+
logProfileFooter(profile, true);
|
|
76
|
+
return profile.accountId;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// A profile must be specified if this project has profiles configured
|
|
80
|
+
await exitIfUsingProfiles(projectConfig, projectDir);
|
|
81
|
+
}
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
@@ -228,7 +228,7 @@ function makePollTaskStatusFunc({ statusFn, structureFn, statusText, statusStrin
|
|
|
228
228
|
}
|
|
229
229
|
function pollBuildAutodeployStatus(accountId, taskName, buildId) {
|
|
230
230
|
return new Promise((resolve, reject) => {
|
|
231
|
-
let maxIntervals = (
|
|
231
|
+
let maxIntervals = (15 * 1000) / constants_1.DEFAULT_POLLING_DELAY; // Num of intervals in ~15s
|
|
232
232
|
const pollInterval = setInterval(async () => {
|
|
233
233
|
let build;
|
|
234
234
|
try {
|
|
@@ -14,9 +14,12 @@ declare class AppDevModeInterface {
|
|
|
14
14
|
private get appNode();
|
|
15
15
|
private get appData();
|
|
16
16
|
private set appData(value);
|
|
17
|
+
private isAutomaticallyInstallable;
|
|
17
18
|
private getAppInstallUrl;
|
|
18
19
|
private fetchAppData;
|
|
19
20
|
private checkMarketplaceAppInstalls;
|
|
21
|
+
private autoInstallStaticAuthApp;
|
|
22
|
+
private installAppOrOpenInstallUrl;
|
|
20
23
|
private checkTestAccountAppInstallation;
|
|
21
24
|
private setUpLocalDevServerMessageListeners;
|
|
22
25
|
setup(args: any): Promise<void>;
|
|
@@ -4,6 +4,7 @@ const localDevAuth_1 = require("@hubspot/local-dev-lib/api/localDevAuth");
|
|
|
4
4
|
const appsDev_1 = require("@hubspot/local-dev-lib/api/appsDev");
|
|
5
5
|
const ui_extensions_dev_server_1 = require("@hubspot/ui-extensions-dev-server");
|
|
6
6
|
const portManager_1 = require("@hubspot/local-dev-lib/portManager");
|
|
7
|
+
const config_1 = require("@hubspot/local-dev-lib/config");
|
|
7
8
|
const constants_1 = require("../../constants");
|
|
8
9
|
const exitCodes_1 = require("../../enums/exitCodes");
|
|
9
10
|
const structure_1 = require("../../projects/structure");
|
|
@@ -14,6 +15,7 @@ const promptUtils_1 = require("../../prompts/promptUtils");
|
|
|
14
15
|
const en_1 = require("../../../lang/en");
|
|
15
16
|
const logger_1 = require("../../ui/logger");
|
|
16
17
|
const urls_1 = require("../../app/urls");
|
|
18
|
+
const accountTypes_1 = require("../../accountTypes");
|
|
17
19
|
class AppDevModeInterface {
|
|
18
20
|
localDevState;
|
|
19
21
|
localDevLogger;
|
|
@@ -22,15 +24,6 @@ class AppDevModeInterface {
|
|
|
22
24
|
constructor(options) {
|
|
23
25
|
this.localDevState = options.localDevState;
|
|
24
26
|
this.localDevLogger = options.localDevLogger;
|
|
25
|
-
// Static auth apps are currently only installable in the portal that the project resides in
|
|
26
|
-
// This limitation will eventually be removed, but in the meantime we need this check or the install
|
|
27
|
-
// will always fail with a confusing message
|
|
28
|
-
if (this.appNode?.config.auth.type === constants_1.APP_AUTH_TYPES.STATIC &&
|
|
29
|
-
this.localDevState.targetTestingAccountId !==
|
|
30
|
-
this.localDevState.targetProjectAccountId) {
|
|
31
|
-
logger_1.uiLogger.error(en_1.lib.LocalDevManager.staticAuthAccountsMustMatch);
|
|
32
|
-
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
33
|
-
}
|
|
34
27
|
if (!this.localDevState.targetProjectAccountId ||
|
|
35
28
|
!this.localDevState.projectConfig ||
|
|
36
29
|
!this.localDevState.projectDir) {
|
|
@@ -59,6 +52,19 @@ class AppDevModeInterface {
|
|
|
59
52
|
}
|
|
60
53
|
this.localDevState.setAppDataForUid(this.appNode.uid, appData);
|
|
61
54
|
}
|
|
55
|
+
isAutomaticallyInstallable() {
|
|
56
|
+
const targetTestingAccount = (0, config_1.getAccountConfig)(this.localDevState.targetTestingAccountId);
|
|
57
|
+
if (!targetTestingAccount) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
const isTestAccount = (0, accountTypes_1.isDeveloperTestAccount)(targetTestingAccount) ||
|
|
61
|
+
(0, accountTypes_1.isSandbox)(targetTestingAccount);
|
|
62
|
+
const hasCorrectParent = targetTestingAccount.parentAccountId ===
|
|
63
|
+
this.localDevState.targetProjectAccountId;
|
|
64
|
+
return (isTestAccount &&
|
|
65
|
+
hasCorrectParent &&
|
|
66
|
+
this.appNode?.config.auth.type === constants_1.APP_AUTH_TYPES.STATIC);
|
|
67
|
+
}
|
|
62
68
|
async getAppInstallUrl() {
|
|
63
69
|
if (this.appNode?.config.auth.type === constants_1.APP_AUTH_TYPES.OAUTH) {
|
|
64
70
|
return (0, urls_1.getOauthAppInstallUrl)({
|
|
@@ -72,7 +78,7 @@ class AppDevModeInterface {
|
|
|
72
78
|
const { data: { results }, } = await (0, appsDev_1.fetchPublicAppsForPortal)(this.localDevState.targetProjectAccountId);
|
|
73
79
|
const app = results.find(app => app.sourceId === this.appNode?.uid);
|
|
74
80
|
if (!app) {
|
|
75
|
-
logger_1.uiLogger.error(en_1.lib.LocalDevManager.
|
|
81
|
+
logger_1.uiLogger.error(en_1.lib.LocalDevManager.appNotFound(this.localDevState.targetProjectAccountId, this.appNode?.uid));
|
|
76
82
|
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
77
83
|
}
|
|
78
84
|
return (0, urls_1.getStaticAuthAppInstallUrl)({
|
|
@@ -93,6 +99,7 @@ class AppDevModeInterface {
|
|
|
93
99
|
clientId: appData.clientId,
|
|
94
100
|
name: appData.name,
|
|
95
101
|
installationState: constants_1.APP_INSTALLATION_STATES.NOT_INSTALLED,
|
|
102
|
+
scopeGroupIds: appData.scopeGroupIds,
|
|
96
103
|
};
|
|
97
104
|
this.marketplaceAppInstalls = uniquePortalInstallCount;
|
|
98
105
|
}
|
|
@@ -110,9 +117,31 @@ class AppDevModeInterface {
|
|
|
110
117
|
}
|
|
111
118
|
this.localDevLogger.addUploadWarning(en_1.lib.AppDevModeInterface.defaultMarketplaceAppWarning(this.marketplaceAppInstalls));
|
|
112
119
|
}
|
|
120
|
+
async autoInstallStaticAuthApp() {
|
|
121
|
+
const shouldInstall = await (0, installAppPrompt_1.installAppAutoPrompt)();
|
|
122
|
+
if (!shouldInstall) {
|
|
123
|
+
logger_1.uiLogger.log(en_1.lib.AppDevModeInterface.autoInstallDeclined);
|
|
124
|
+
process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
125
|
+
}
|
|
126
|
+
await (0, appsDev_1.installStaticAuthAppOnTestAccount)(this.appData.id, this.localDevState.targetTestingAccountId, this.appData.scopeGroupIds);
|
|
127
|
+
}
|
|
128
|
+
async installAppOrOpenInstallUrl(isReinstall) {
|
|
129
|
+
if (this.isAutomaticallyInstallable()) {
|
|
130
|
+
try {
|
|
131
|
+
await this.autoInstallStaticAuthApp();
|
|
132
|
+
logger_1.uiLogger.success(en_1.lib.AppDevModeInterface.autoInstallSuccess(this.appData.name, this.localDevState.targetTestingAccountId));
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
logger_1.uiLogger.error(en_1.lib.AppDevModeInterface.autoInstallError(this.appData.name, this.localDevState.targetTestingAccountId));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const installUrl = await this.getAppInstallUrl();
|
|
140
|
+
await (0, installAppPrompt_1.installAppBrowserPrompt)(installUrl, isReinstall);
|
|
141
|
+
}
|
|
113
142
|
async checkTestAccountAppInstallation() {
|
|
114
143
|
if (!this.appNode || !this.appData) {
|
|
115
|
-
return;
|
|
144
|
+
return {};
|
|
116
145
|
}
|
|
117
146
|
const { data: { isInstalledWithScopeGroups, previouslyAuthorizedScopeGroups }, } = await (0, localDevAuth_1.fetchAppInstallationData)(this.localDevState.targetTestingAccountId, this.localDevState.projectId, this.appNode.uid, this.appNode.config.auth.requiredScopes, this.appNode.config.auth.optionalScopes);
|
|
118
147
|
const isReinstall = previouslyAuthorizedScopeGroups.length > 0;
|
|
@@ -128,10 +157,7 @@ class AppDevModeInterface {
|
|
|
128
157
|
installationState: constants_1.APP_INSTALLATION_STATES.INSTALLED_WITH_OUTDATED_SCOPES,
|
|
129
158
|
};
|
|
130
159
|
}
|
|
131
|
-
|
|
132
|
-
const installUrl = await this.getAppInstallUrl();
|
|
133
|
-
await (0, installAppPrompt_1.installAppPrompt)(installUrl, isReinstall);
|
|
134
|
-
}
|
|
160
|
+
return { needsInstall: !isInstalledWithScopeGroups, isReinstall };
|
|
135
161
|
}
|
|
136
162
|
setUpLocalDevServerMessageListeners() {
|
|
137
163
|
this.localDevState.addListener('devServerMessage', message => {
|
|
@@ -151,7 +177,10 @@ class AppDevModeInterface {
|
|
|
151
177
|
if (this.appNode.config.distribution === constants_1.APP_DISTRIBUTION_TYPES.MARKETPLACE) {
|
|
152
178
|
await this.checkMarketplaceAppInstalls();
|
|
153
179
|
}
|
|
154
|
-
await this.checkTestAccountAppInstallation();
|
|
180
|
+
const { needsInstall, isReinstall } = await this.checkTestAccountAppInstallation();
|
|
181
|
+
if (needsInstall) {
|
|
182
|
+
await this.installAppOrOpenInstallUrl(isReinstall || false);
|
|
183
|
+
}
|
|
155
184
|
}
|
|
156
185
|
catch (e) {
|
|
157
186
|
(0, index_1.logError)(e);
|
|
@@ -195,7 +195,7 @@ class LocalDevManager {
|
|
|
195
195
|
scopes: this.activeApp.config.auth.requiredScopes,
|
|
196
196
|
redirectUrls: this.activeApp.config.auth.redirectUrls,
|
|
197
197
|
});
|
|
198
|
-
await (0, installAppPrompt_1.
|
|
198
|
+
await (0, installAppPrompt_1.installAppBrowserPrompt)(installUrl, isReinstall);
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
updateKeypressListeners() {
|
package/lib/projects/upload.d.ts
CHANGED
|
@@ -18,4 +18,7 @@ type HandleProjectUploadArg<T> = {
|
|
|
18
18
|
profile?: string;
|
|
19
19
|
};
|
|
20
20
|
export declare function handleProjectUpload<T>({ accountId, projectConfig, projectDir, callbackFunc, profile, uploadMessage, forceCreate, isUploadCommand, sendIR, skipValidation, }: HandleProjectUploadArg<T>): Promise<ProjectUploadResult<T>>;
|
|
21
|
+
export declare function validateSourceDirectory(srcDir: string, projectConfig: ProjectConfig): void;
|
|
22
|
+
export declare function validateNoHSMetaMismatch(srcDir: string, projectConfig: ProjectConfig): Promise<void>;
|
|
23
|
+
export declare function handleTranslate(projectDir: string, projectConfig: ProjectConfig, accountId: number, skipValidation: boolean, profile: string | undefined): Promise<unknown>;
|
|
21
24
|
export {};
|
package/lib/projects/upload.js
CHANGED
|
@@ -4,22 +4,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.handleProjectUpload = handleProjectUpload;
|
|
7
|
+
exports.validateSourceDirectory = validateSourceDirectory;
|
|
8
|
+
exports.validateNoHSMetaMismatch = validateNoHSMetaMismatch;
|
|
9
|
+
exports.handleTranslate = handleTranslate;
|
|
7
10
|
const archiver_1 = __importDefault(require("archiver"));
|
|
8
11
|
const tmp_1 = __importDefault(require("tmp"));
|
|
9
12
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
13
|
const path_1 = __importDefault(require("path"));
|
|
11
14
|
const projects_1 = require("@hubspot/local-dev-lib/api/projects");
|
|
12
15
|
const ignoreRules_1 = require("@hubspot/local-dev-lib/ignoreRules");
|
|
16
|
+
const project_parsing_lib_1 = require("@hubspot/project-parsing-lib");
|
|
13
17
|
const SpinniesManager_1 = __importDefault(require("../ui/SpinniesManager"));
|
|
14
18
|
const ui_1 = require("../ui");
|
|
15
|
-
const exitCodes_1 = require("../enums/exitCodes");
|
|
16
|
-
const project_parsing_lib_1 = require("@hubspot/project-parsing-lib");
|
|
17
19
|
const errorHandlers_1 = require("../errorHandlers");
|
|
18
20
|
const node_util_1 = __importDefault(require("node:util"));
|
|
19
21
|
const en_1 = require("../../lang/en");
|
|
20
22
|
const ensureProjectExists_1 = require("./ensureProjectExists");
|
|
21
23
|
const logger_1 = require("../ui/logger");
|
|
22
24
|
const buildAndDeploy_1 = require("./buildAndDeploy");
|
|
25
|
+
const exitCodes_1 = require("../enums/exitCodes");
|
|
23
26
|
async function uploadProjectFiles(accountId, projectName, filePath, uploadMessage, platformVersion, intermediateRepresentation) {
|
|
24
27
|
SpinniesManager_1.default.init({});
|
|
25
28
|
const accountIdentifier = (0, ui_1.uiAccountDescription)(accountId);
|
|
@@ -49,14 +52,18 @@ async function uploadProjectFiles(accountId, projectName, filePath, uploadMessag
|
|
|
49
52
|
}
|
|
50
53
|
async function handleProjectUpload({ accountId, projectConfig, projectDir, callbackFunc, profile, uploadMessage = '', forceCreate = false, isUploadCommand = false, sendIR = false, skipValidation = false, }) {
|
|
51
54
|
const srcDir = path_1.default.resolve(projectDir, projectConfig.srcDir);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
logger_1.uiLogger.log(en_1.lib.projectUpload.handleProjectUpload.emptySource(projectConfig.srcDir));
|
|
55
|
-
process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
55
|
+
try {
|
|
56
|
+
validateSourceDirectory(srcDir, projectConfig);
|
|
56
57
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
catch (e) {
|
|
59
|
+
(0, errorHandlers_1.logError)(e);
|
|
60
|
+
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
await validateNoHSMetaMismatch(srcDir, projectConfig);
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
(0, errorHandlers_1.logError)(e);
|
|
60
67
|
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
61
68
|
}
|
|
62
69
|
const tempFile = tmp_1.default.fileSync({ postfix: '.zip' });
|
|
@@ -68,21 +75,11 @@ async function handleProjectUpload({ accountId, projectConfig, projectDir, callb
|
|
|
68
75
|
let intermediateRepresentation;
|
|
69
76
|
if (sendIR) {
|
|
70
77
|
try {
|
|
71
|
-
intermediateRepresentation = await (
|
|
72
|
-
projectSourceDir: path_1.default.join(projectDir, projectConfig.srcDir),
|
|
73
|
-
platformVersion: projectConfig.platformVersion,
|
|
74
|
-
accountId,
|
|
75
|
-
}, { skipValidation, profile });
|
|
76
|
-
logger_1.uiLogger.debug(node_util_1.default.inspect(intermediateRepresentation, false, null, true));
|
|
78
|
+
intermediateRepresentation = await handleTranslate(projectDir, projectConfig, accountId, skipValidation, profile);
|
|
77
79
|
}
|
|
78
80
|
catch (e) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
(0, errorHandlers_1.logError)(e);
|
|
84
|
-
}
|
|
85
|
-
return process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
81
|
+
(0, errorHandlers_1.logError)(e);
|
|
82
|
+
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
86
83
|
}
|
|
87
84
|
}
|
|
88
85
|
await (0, ensureProjectExists_1.ensureProjectExists)(accountId, projectConfig.name, {
|
|
@@ -116,3 +113,40 @@ async function handleProjectUpload({ accountId, projectConfig, projectDir, callb
|
|
|
116
113
|
archive.finalize();
|
|
117
114
|
return result;
|
|
118
115
|
}
|
|
116
|
+
function validateSourceDirectory(srcDir, projectConfig) {
|
|
117
|
+
const filenames = fs_extra_1.default.readdirSync(srcDir);
|
|
118
|
+
if (!filenames || filenames.length === 0) {
|
|
119
|
+
const validationError = new Error(en_1.lib.projectUpload.handleProjectUpload.emptySource(projectConfig.srcDir));
|
|
120
|
+
validationError.name = 'ProjectValidationError';
|
|
121
|
+
throw validationError;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async function validateNoHSMetaMismatch(srcDir, projectConfig) {
|
|
125
|
+
const hasHsMetaFiles = await (0, project_parsing_lib_1.projectContainsHsMetaFiles)(srcDir);
|
|
126
|
+
if (!(0, buildAndDeploy_1.useV3Api)(projectConfig.platformVersion) && hasHsMetaFiles) {
|
|
127
|
+
const validationError = new Error(en_1.lib.projectUpload.wrongPlatformVersionMetaFiles);
|
|
128
|
+
validationError.name = 'ProjectValidationError';
|
|
129
|
+
throw validationError;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function handleTranslate(projectDir, projectConfig, accountId, skipValidation, profile) {
|
|
133
|
+
try {
|
|
134
|
+
const intermediateRepresentation = await (0, project_parsing_lib_1.translate)({
|
|
135
|
+
projectSourceDir: path_1.default.join(projectDir, projectConfig.srcDir),
|
|
136
|
+
platformVersion: projectConfig.platformVersion,
|
|
137
|
+
accountId,
|
|
138
|
+
}, { skipValidation, profile });
|
|
139
|
+
logger_1.uiLogger.debug(node_util_1.default.inspect(intermediateRepresentation, false, null, true));
|
|
140
|
+
return intermediateRepresentation;
|
|
141
|
+
}
|
|
142
|
+
catch (e) {
|
|
143
|
+
if ((0, project_parsing_lib_1.isTranslationError)(e)) {
|
|
144
|
+
const validationError = new Error(e.toString());
|
|
145
|
+
validationError.name = 'ProjectValidationError';
|
|
146
|
+
throw validationError;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
(0, errorHandlers_1.logError)(e);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
package/lib/projects/urls.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export declare function getProjectComponentDistributionUrl(projectName: string, componentName: string, accountId: number): string;
|
|
2
|
+
export declare function getDeveloperOverviewUrl(accountId: number): string;
|
|
1
3
|
export declare function getProjectDetailUrl(projectName: string, accountId: number): string | undefined;
|
|
2
4
|
export declare function getProjectSettingsUrl(projectName: string, accountId: number): string | undefined;
|
|
3
5
|
export declare function getProjectActivityUrl(projectName: string, accountId: number): string;
|
package/lib/projects/urls.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getProjectComponentDistributionUrl = getProjectComponentDistributionUrl;
|
|
4
|
+
exports.getDeveloperOverviewUrl = getDeveloperOverviewUrl;
|
|
3
5
|
exports.getProjectDetailUrl = getProjectDetailUrl;
|
|
4
6
|
exports.getProjectSettingsUrl = getProjectSettingsUrl;
|
|
5
7
|
exports.getProjectActivityUrl = getProjectActivityUrl;
|
|
@@ -15,6 +17,14 @@ function getBaseUrl(accountId) {
|
|
|
15
17
|
function getProjectHomeUrl(accountId) {
|
|
16
18
|
return `${getBaseUrl(accountId)}/developer-projects/${accountId}`;
|
|
17
19
|
}
|
|
20
|
+
function getProjectComponentDistributionUrl(projectName, componentName, accountId) {
|
|
21
|
+
const baseUrl = (0, urls_1.getHubSpotWebsiteOrigin)((0, config_1.getEnv)(accountId) === 'qa' ? environments_1.ENVIRONMENTS.QA : environments_1.ENVIRONMENTS.PROD);
|
|
22
|
+
return `${baseUrl}/developer-projects/${accountId}/project/${projectName}/component/${componentName}/distribution`;
|
|
23
|
+
}
|
|
24
|
+
function getDeveloperOverviewUrl(accountId) {
|
|
25
|
+
const baseUrl = (0, urls_1.getHubSpotWebsiteOrigin)((0, config_1.getEnv)(accountId) === 'qa' ? environments_1.ENVIRONMENTS.QA : environments_1.ENVIRONMENTS.PROD);
|
|
26
|
+
return `${baseUrl}/developer-overview/${accountId}`;
|
|
27
|
+
}
|
|
18
28
|
function getProjectDetailUrl(projectName, accountId) {
|
|
19
29
|
if (!projectName)
|
|
20
30
|
return;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { DeveloperTestAccountConfig } from '@hubspot/local-dev-lib/types/developerTestAccounts';
|
|
2
|
+
declare const hubs: {
|
|
3
|
+
readonly MARKETING: "marketingLevel";
|
|
4
|
+
readonly OPS: "opsLevel";
|
|
5
|
+
readonly SERVICE: "serviceLevel";
|
|
6
|
+
readonly SALES: "salesLevel";
|
|
7
|
+
readonly CONTENT: "contentLevel";
|
|
8
|
+
};
|
|
9
|
+
type HubName = keyof typeof hubs;
|
|
10
|
+
type HubTier = 'STARTER' | 'PROFESSIONAL' | 'ENTERPRISE';
|
|
11
|
+
export type HubConfig = `${HubName}:${HubTier}`;
|
|
12
|
+
export declare function createDeveloperTestAccountConfigPrompt(args?: {
|
|
13
|
+
name?: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
tiers?: HubConfig[];
|
|
16
|
+
}): Promise<DeveloperTestAccountConfig>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createDeveloperTestAccountConfigPrompt = createDeveloperTestAccountConfigPrompt;
|
|
4
|
+
const en_1 = require("../../lang/en");
|
|
5
|
+
const promptUtils_1 = require("./promptUtils");
|
|
6
|
+
const hubs = {
|
|
7
|
+
MARKETING: 'marketingLevel',
|
|
8
|
+
OPS: 'opsLevel',
|
|
9
|
+
SERVICE: 'serviceLevel',
|
|
10
|
+
SALES: 'salesLevel',
|
|
11
|
+
CONTENT: 'contentLevel',
|
|
12
|
+
};
|
|
13
|
+
const TEST_ACCOUNT_TIERS = [
|
|
14
|
+
{ name: 'Marketing STARTER', value: 'MARKETING:STARTER' },
|
|
15
|
+
{
|
|
16
|
+
name: 'Marketing PROFESSIONAL',
|
|
17
|
+
value: 'MARKETING:PROFESSIONAL',
|
|
18
|
+
},
|
|
19
|
+
{ name: 'Marketing ENTERPRISE', value: 'MARKETING:ENTERPRISE' },
|
|
20
|
+
promptUtils_1.Separator,
|
|
21
|
+
{ name: 'Ops STARTER', value: 'OPS:STARTER' },
|
|
22
|
+
{ name: 'Ops PROFESSIONAL', value: 'OPS:PROFESSIONAL' },
|
|
23
|
+
{ name: 'Ops ENTERPRISE', value: 'OPS:ENTERPRISE' },
|
|
24
|
+
promptUtils_1.Separator,
|
|
25
|
+
{ name: 'Service STARTER', value: 'SERVICE:STARTER' },
|
|
26
|
+
{ name: 'Service PROFESSIONAL', value: 'SERVICE:PROFESSIONAL' },
|
|
27
|
+
{ name: 'Service ENTERPRISE', value: 'SERVICE:ENTERPRISE' },
|
|
28
|
+
promptUtils_1.Separator,
|
|
29
|
+
{ name: 'Sales STARTER', value: 'SALES:STARTER' },
|
|
30
|
+
{ name: 'Sales PROFESSIONAL', value: 'SALES:PROFESSIONAL' },
|
|
31
|
+
{ name: 'Sales ENTERPRISE', value: 'SALES:ENTERPRISE' },
|
|
32
|
+
promptUtils_1.Separator,
|
|
33
|
+
{ name: 'Content STARTER', value: 'CONTENT:STARTER' },
|
|
34
|
+
{ name: 'Content PROFESSIONAL', value: 'CONTENT:PROFESSIONAL' },
|
|
35
|
+
{ name: 'Content ENTERPRISE', value: 'CONTENT:ENTERPRISE' },
|
|
36
|
+
promptUtils_1.Separator,
|
|
37
|
+
];
|
|
38
|
+
async function createDeveloperTestAccountConfigPrompt(args = {}) {
|
|
39
|
+
const { name, description, tiers } = args;
|
|
40
|
+
let accountName = name;
|
|
41
|
+
let accountDescription = description;
|
|
42
|
+
let accountLevelsArray = tiers;
|
|
43
|
+
if (!accountName) {
|
|
44
|
+
const namePromptResult = await (0, promptUtils_1.promptUser)({
|
|
45
|
+
name: 'accountName',
|
|
46
|
+
message: en_1.lib.prompts.createDeveloperTestAccountConfigPrompt.namePrompt,
|
|
47
|
+
type: 'input',
|
|
48
|
+
});
|
|
49
|
+
accountName = namePromptResult.accountName;
|
|
50
|
+
}
|
|
51
|
+
if (!accountDescription) {
|
|
52
|
+
const descriptionPromptResult = await (0, promptUtils_1.promptUser)({
|
|
53
|
+
name: 'description',
|
|
54
|
+
message: en_1.lib.prompts.createDeveloperTestAccountConfigPrompt.descriptionPrompt,
|
|
55
|
+
type: 'input',
|
|
56
|
+
});
|
|
57
|
+
accountDescription = descriptionPromptResult.description;
|
|
58
|
+
}
|
|
59
|
+
if (!accountLevelsArray) {
|
|
60
|
+
const accountLevelsPromptResult = await (0, promptUtils_1.promptUser)({
|
|
61
|
+
name: 'testAccountLevels',
|
|
62
|
+
message: en_1.lib.prompts.createDeveloperTestAccountConfigPrompt.tiersPrompt,
|
|
63
|
+
type: 'checkbox',
|
|
64
|
+
choices: TEST_ACCOUNT_TIERS,
|
|
65
|
+
validate: choices => {
|
|
66
|
+
if (choices?.length > 1) {
|
|
67
|
+
const hubMap = {};
|
|
68
|
+
for (const choice of choices) {
|
|
69
|
+
const hub = choice.split(':')[0];
|
|
70
|
+
if (hubMap[hub]) {
|
|
71
|
+
return en_1.lib.prompts.createDeveloperTestAccountConfigPrompt.errors
|
|
72
|
+
.tiersError;
|
|
73
|
+
}
|
|
74
|
+
hubMap[hub] = true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return true;
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
accountLevelsArray = accountLevelsPromptResult.testAccountLevels;
|
|
81
|
+
}
|
|
82
|
+
if (!accountLevelsArray) {
|
|
83
|
+
accountLevelsArray = [];
|
|
84
|
+
}
|
|
85
|
+
const accountLevels = accountLevelsArray.reduce((acc, level) => {
|
|
86
|
+
const [hubName, hubTier] = level.split(':');
|
|
87
|
+
const hubLevel = hubs[hubName];
|
|
88
|
+
acc[hubLevel] = hubTier;
|
|
89
|
+
return acc;
|
|
90
|
+
}, {});
|
|
91
|
+
return {
|
|
92
|
+
accountName: accountName,
|
|
93
|
+
description: accountDescription,
|
|
94
|
+
...accountLevels,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export declare function
|
|
1
|
+
export declare function installAppBrowserPrompt(installUrl: string, isReinstall?: boolean): Promise<void>;
|
|
2
|
+
export declare function installAppAutoPrompt(): Promise<boolean>;
|
|
@@ -3,13 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.installAppBrowserPrompt = installAppBrowserPrompt;
|
|
7
|
+
exports.installAppAutoPrompt = installAppAutoPrompt;
|
|
7
8
|
const open_1 = __importDefault(require("open"));
|
|
8
9
|
const promptUtils_1 = require("./promptUtils");
|
|
9
10
|
const exitCodes_1 = require("../enums/exitCodes");
|
|
10
11
|
const en_1 = require("../../lang/en");
|
|
11
12
|
const logger_1 = require("../ui/logger");
|
|
12
|
-
async function
|
|
13
|
+
async function installAppBrowserPrompt(installUrl, isReinstall = false) {
|
|
13
14
|
logger_1.uiLogger.log('');
|
|
14
15
|
if (isReinstall) {
|
|
15
16
|
logger_1.uiLogger.log(en_1.lib.prompts.installAppPrompt.reinstallExplanation);
|
|
@@ -33,3 +34,12 @@ async function installAppPrompt(installUrl, isReinstall = false) {
|
|
|
33
34
|
}
|
|
34
35
|
(0, open_1.default)(installUrl);
|
|
35
36
|
}
|
|
37
|
+
async function installAppAutoPrompt() {
|
|
38
|
+
logger_1.uiLogger.log('');
|
|
39
|
+
const { shouldInstall } = await (0, promptUtils_1.promptUser)({
|
|
40
|
+
name: 'shouldInstall',
|
|
41
|
+
type: 'confirm',
|
|
42
|
+
message: en_1.lib.prompts.installAppPrompt.autoPrompt,
|
|
43
|
+
});
|
|
44
|
+
return shouldInstall;
|
|
45
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PromptConfig, GenericPromptResponse, PromptWhen, PromptChoices } from '../../types/Prompts';
|
|
2
|
+
export declare const Separator: any;
|
|
2
3
|
export declare function promptUser<T extends GenericPromptResponse>(config: PromptConfig<T> | PromptConfig<T>[]): Promise<T>;
|
|
3
4
|
export declare function confirmPrompt(message: string, options?: {
|
|
4
5
|
defaultAnswer?: boolean;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Separator = void 0;
|
|
3
4
|
exports.promptUser = promptUser;
|
|
4
5
|
exports.confirmPrompt = confirmPrompt;
|
|
5
6
|
exports.listPrompt = listPrompt;
|
|
6
7
|
exports.inputPrompt = inputPrompt;
|
|
7
8
|
const inquirer = require('inquirer');
|
|
8
9
|
const promptModule = inquirer.createPromptModule();
|
|
10
|
+
exports.Separator = new inquirer.Separator();
|
|
9
11
|
function promptUser(config) {
|
|
10
12
|
return promptModule(config);
|
|
11
13
|
}
|