@hubspot/cli 8.0.10-experimental.0 → 8.0.10-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/commands/cms/__tests__/watch.test.js +0 -8
- package/commands/cms/function/logs.js +1 -0
- package/commands/cms/watch.d.ts +0 -1
- package/commands/cms/watch.js +2 -8
- package/commands/feedback.js +1 -1
- package/commands/mcp/__tests__/start.test.js +8 -1
- package/commands/mcp/setup.js +1 -9
- package/commands/mcp/start.js +0 -1
- package/commands/project/__tests__/create.test.js +1 -1
- package/commands/project/create.js +2 -2
- package/commands/project/watch.js +15 -2
- package/lang/en.d.ts +2 -6
- package/lang/en.js +2 -6
- package/lib/__tests__/serverlessLogs.test.js +71 -65
- package/lib/constants.d.ts +1 -1
- package/lib/constants.js +1 -1
- package/lib/generateSelectors.js +1 -2
- package/lib/mcp/__tests__/setup.test.js +357 -28
- package/lib/mcp/setup.d.ts +1 -0
- package/lib/mcp/setup.js +77 -30
- package/lib/projects/create/__tests__/legacy.test.js +6 -24
- package/lib/projects/create/index.js +1 -4
- package/lib/projects/create/legacy.js +3 -8
- package/lib/projects/create/v2.js +1 -9
- package/lib/projects/ensureProjectExists.js +1 -2
- package/lib/projects/pollProjectBuildAndDeploy.js +90 -85
- package/lib/projects/upload.d.ts +1 -0
- package/lib/projects/upload.js +37 -46
- package/lib/projects/watch.d.ts +2 -1
- package/lib/projects/watch.js +32 -24
- package/lib/serverlessLogs.js +50 -44
- package/mcp-server/tools/cms/HsCreateFunctionTool.js +1 -1
- package/mcp-server/tools/cms/HsCreateModuleTool.js +1 -1
- package/mcp-server/tools/cms/HsCreateTemplateTool.js +1 -1
- package/mcp-server/tools/cms/HsFunctionLogsTool.js +1 -1
- package/mcp-server/tools/cms/HsListFunctionsTool.js +1 -1
- package/mcp-server/tools/cms/HsListTool.js +1 -1
- package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +1 -2
- package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.js +1 -2
- package/mcp-server/tools/cms/__tests__/HsCreateTemplateTool.test.js +1 -2
- package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.js +1 -2
- package/mcp-server/tools/cms/__tests__/HsListFunctionsTool.test.js +1 -2
- package/mcp-server/tools/cms/__tests__/HsListTool.test.js +1 -2
- package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +1 -1
- package/mcp-server/tools/project/AddFeatureToProjectTool.js +1 -1
- package/mcp-server/tools/project/CreateProjectTool.d.ts +1 -1
- package/mcp-server/tools/project/CreateProjectTool.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/UploadProjectTools.js +1 -1
- package/mcp-server/tools/project/ValidateProjectTool.js +1 -1
- package/mcp-server/tools/project/__tests__/AddFeatureToProjectTool.test.js +1 -2
- package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +1 -2
- package/mcp-server/tools/project/__tests__/CreateTestAccountTool.test.js +1 -2
- package/mcp-server/tools/project/__tests__/DeployProjectTool.test.js +1 -2
- package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +10 -2
- package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +2 -2
- package/mcp-server/tools/project/constants.d.ts +1 -1
- package/mcp-server/utils/__tests__/command.test.js +233 -3
- package/mcp-server/utils/__tests__/feedbackTracking.test.js +9 -64
- package/mcp-server/utils/command.d.ts +5 -0
- package/mcp-server/utils/command.js +24 -0
- package/mcp-server/utils/feedbackTracking.js +2 -17
- package/package.json +5 -10
- package/mcp-server/utils/__tests__/project.test.d.ts +0 -1
- package/mcp-server/utils/__tests__/project.test.js +0 -140
- package/mcp-server/utils/project.d.ts +0 -5
- package/mcp-server/utils/project.js +0 -18
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { fetchRepoFile } from '@hubspot/local-dev-lib/api/github';
|
|
2
2
|
import { DEFAULT_PROJECT_TEMPLATE_BRANCH, HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, PROJECT_COMPONENT_TYPES, } from '../../constants.js';
|
|
3
|
-
import { EXIT_CODES } from '../../enums/exitCodes.js';
|
|
4
3
|
import { debugError } from '../../errorHandlers/index.js';
|
|
5
|
-
import { uiLogger } from '../../ui/logger.js';
|
|
6
4
|
import { isV2Project } from '../platformVersion.js';
|
|
7
5
|
import { lib } from '../../../lang/en.js';
|
|
8
6
|
const PROJECT_TEMPLATE_PROPERTIES = ['name', 'label', 'path'];
|
|
@@ -36,18 +34,15 @@ export async function getProjectTemplateListFromRepo(templateSource, githubRef)
|
|
|
36
34
|
}
|
|
37
35
|
catch (e) {
|
|
38
36
|
debugError(e);
|
|
39
|
-
|
|
40
|
-
return process.exit(EXIT_CODES.ERROR);
|
|
37
|
+
throw new Error(lib.projects.create.errors.missingConfigFileTemplateSource);
|
|
41
38
|
}
|
|
42
39
|
if (!config || !config[PROJECT_COMPONENT_TYPES.PROJECTS]) {
|
|
43
|
-
|
|
44
|
-
return process.exit(EXIT_CODES.ERROR);
|
|
40
|
+
throw new Error(lib.projects.create.errors.noProjectsInConfig);
|
|
45
41
|
}
|
|
46
42
|
const templates = config[PROJECT_COMPONENT_TYPES.PROJECTS];
|
|
47
43
|
const templatesContainAllProperties = templates.every(config => PROJECT_TEMPLATE_PROPERTIES.every(p => Object.prototype.hasOwnProperty.call(config, p)));
|
|
48
44
|
if (!templatesContainAllProperties) {
|
|
49
|
-
|
|
50
|
-
return process.exit(EXIT_CODES.ERROR);
|
|
45
|
+
throw new Error(lib.projects.create.errors.missingPropertiesInConfig);
|
|
51
46
|
}
|
|
52
47
|
return templates;
|
|
53
48
|
}
|
|
@@ -5,8 +5,6 @@ import { APP_EVENTS_KEY as AppEventsKey, PAGES_KEY as PagesKey, } from '@hubspot
|
|
|
5
5
|
import { isV2Project } from '../platformVersion.js';
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import { getConfigForPlatformVersion } from './legacy.js';
|
|
8
|
-
import { logError } from '../../errorHandlers/index.js';
|
|
9
|
-
import { EXIT_CODES } from '../../enums/exitCodes.js';
|
|
10
8
|
import { hasFeature } from '../../hasFeature.js';
|
|
11
9
|
export async function createV2App(providedAuth, providedDistribution) {
|
|
12
10
|
let authType;
|
|
@@ -111,13 +109,7 @@ export async function v2ComponentFlow(platformVersion, projectBase, providedAuth
|
|
|
111
109
|
let repoConfig = undefined;
|
|
112
110
|
let authType;
|
|
113
111
|
let distribution;
|
|
114
|
-
|
|
115
|
-
repoConfig = await getConfigForPlatformVersion(platformVersion);
|
|
116
|
-
}
|
|
117
|
-
catch (error) {
|
|
118
|
-
logError(error);
|
|
119
|
-
return process.exit(EXIT_CODES.SUCCESS);
|
|
120
|
-
}
|
|
112
|
+
repoConfig = await getConfigForPlatformVersion(platformVersion);
|
|
121
113
|
const projectContentsChoice = projectBase ||
|
|
122
114
|
(await listPrompt(commands.project.create.prompts.parentComponents, {
|
|
123
115
|
choices: [
|
|
@@ -2,7 +2,6 @@ import { createProject, fetchProject, } from '@hubspot/local-dev-lib/api/project
|
|
|
2
2
|
import { isSpecifiedError } from '@hubspot/local-dev-lib/errors/index';
|
|
3
3
|
import { DEFAULT_POLLING_DELAY } from '../constants.js';
|
|
4
4
|
import { promptUser } from '../prompts/promptUtils.js';
|
|
5
|
-
import { EXIT_CODES } from '../enums/exitCodes.js';
|
|
6
5
|
import { uiAccountDescription } from '../ui/index.js';
|
|
7
6
|
import SpinniesManager from '../ui/SpinniesManager.js';
|
|
8
7
|
import { logError, ApiErrorContext } from '../errorHandlers/index.js';
|
|
@@ -85,6 +84,6 @@ export async function ensureProjectExists(accountId, projectName, { forceCreate
|
|
|
85
84
|
}
|
|
86
85
|
}
|
|
87
86
|
logError(err, new ApiErrorContext({ accountId }));
|
|
88
|
-
|
|
87
|
+
return { projectExists: false };
|
|
89
88
|
}
|
|
90
89
|
}
|
|
@@ -5,7 +5,6 @@ import SpinniesManager from '../ui/SpinniesManager.js';
|
|
|
5
5
|
import { logError, ApiErrorContext } from '../errorHandlers/index.js';
|
|
6
6
|
import { uiLine, uiLink, uiAccountDescription } from '../ui/index.js';
|
|
7
7
|
import { getProjectBuildDetailUrl, getProjectDeployDetailUrl, getProjectActivityUrl, } from './urls.js';
|
|
8
|
-
import { EXIT_CODES } from '../enums/exitCodes.js';
|
|
9
8
|
import { lib } from '../../lang/en.js';
|
|
10
9
|
import { uiLogger } from '../ui/logger.js';
|
|
11
10
|
import { APP_FUNCTIONS_PACKAGE_KEY as AppFunctionsPackageKey } from '@hubspot/project-parsing-lib/constants';
|
|
@@ -32,8 +31,8 @@ function getSubtaskType(task) {
|
|
|
32
31
|
return task.deployType;
|
|
33
32
|
}
|
|
34
33
|
function handleTaskStatusError(statusText) {
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
const taskType = statusText.TYPE_KEY === PROJECT_BUILD_TEXT.TYPE_KEY ? 'build' : 'deploy';
|
|
35
|
+
throw new Error(lib.projectBuildAndDeploy.makePollTaskStatusFunc.errorFetchingTaskStatus(taskType));
|
|
37
36
|
}
|
|
38
37
|
function makePollTaskStatusFunc({ statusFn, structureFn, statusText, statusStrings, linkToHubSpot, }) {
|
|
39
38
|
return async function (accountId, taskName, taskId, deployedBuildId, silenceLogs = false) {
|
|
@@ -111,97 +110,103 @@ function makePollTaskStatusFunc({ statusFn, structureFn, statusText, statusStrin
|
|
|
111
110
|
task.subtasks.forEach((subtask, i) => addTaskSpinner(subtask, 4, i === task.subtasks.length - 1));
|
|
112
111
|
});
|
|
113
112
|
}
|
|
114
|
-
return new Promise(resolve => {
|
|
113
|
+
return new Promise((resolve, reject) => {
|
|
115
114
|
const pollInterval = setInterval(async () => {
|
|
116
|
-
let taskStatus;
|
|
117
115
|
try {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (status === statusText.STATES.SUCCESS ||
|
|
143
|
-
status === statusText.STATES.FAILURE) {
|
|
144
|
-
const taskStatusText = subtask.status === statusText.STATES.SUCCESS
|
|
145
|
-
? lib.projectBuildAndDeploy.makePollTaskStatusFunc
|
|
146
|
-
.successStatusText
|
|
147
|
-
: lib.projectBuildAndDeploy.makePollTaskStatusFunc
|
|
148
|
-
.failedStatusText;
|
|
149
|
-
const hasNewline = spinner?.text?.includes('\n') || Boolean(topLevelTask);
|
|
150
|
-
const updatedText = `${spinner?.text?.replace('\n', '')} ${taskStatusText}${hasNewline ? '\n' : ''}`;
|
|
151
|
-
if (status === statusText.STATES.SUCCESS) {
|
|
152
|
-
SpinniesManager.succeed(id, { text: updatedText });
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
SpinniesManager.fail(id, { text: updatedText });
|
|
116
|
+
let taskStatus;
|
|
117
|
+
try {
|
|
118
|
+
const { data } = await statusFn(accountId, taskName, taskId);
|
|
119
|
+
taskStatus = data;
|
|
120
|
+
}
|
|
121
|
+
catch (e) {
|
|
122
|
+
uiLogger.debug(e);
|
|
123
|
+
logError(e, new ApiErrorContext({
|
|
124
|
+
accountId,
|
|
125
|
+
projectName: taskName,
|
|
126
|
+
}));
|
|
127
|
+
handleTaskStatusError(statusText);
|
|
128
|
+
}
|
|
129
|
+
const subtasks = getSubtasks(taskStatus);
|
|
130
|
+
if (!taskStatus || !taskStatus.status || !subtasks) {
|
|
131
|
+
handleTaskStatusError(statusText);
|
|
132
|
+
}
|
|
133
|
+
const { status } = taskStatus;
|
|
134
|
+
if (SpinniesManager.hasActiveSpinners()) {
|
|
135
|
+
subtasks.forEach(subtask => {
|
|
136
|
+
const { id, status } = subtask;
|
|
137
|
+
const spinner = SpinniesManager.pick(id);
|
|
138
|
+
if (!spinner || spinner.status !== SPINNER_STATUS.SPINNING) {
|
|
139
|
+
return;
|
|
156
140
|
}
|
|
157
|
-
|
|
158
|
-
|
|
141
|
+
const topLevelTask = structuredTasks.find(t => t.id == id);
|
|
142
|
+
if (status === statusText.STATES.SUCCESS ||
|
|
143
|
+
status === statusText.STATES.FAILURE) {
|
|
144
|
+
const taskStatusText = subtask.status === statusText.STATES.SUCCESS
|
|
145
|
+
? lib.projectBuildAndDeploy.makePollTaskStatusFunc
|
|
146
|
+
.successStatusText
|
|
147
|
+
: lib.projectBuildAndDeploy.makePollTaskStatusFunc
|
|
148
|
+
.failedStatusText;
|
|
149
|
+
const hasNewline = spinner?.text?.includes('\n') || Boolean(topLevelTask);
|
|
150
|
+
const updatedText = `${spinner?.text?.replace('\n', '')} ${taskStatusText}${hasNewline ? '\n' : ''}`;
|
|
151
|
+
if (status === statusText.STATES.SUCCESS) {
|
|
152
|
+
SpinniesManager.succeed(id, { text: updatedText });
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
SpinniesManager.fail(id, { text: updatedText });
|
|
156
|
+
}
|
|
157
|
+
if (topLevelTask) {
|
|
158
|
+
topLevelTask.subtasks.forEach(currentSubtask => SpinniesManager.remove(currentSubtask.id));
|
|
159
|
+
}
|
|
159
160
|
}
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
if (status === statusText.STATES.SUCCESS) {
|
|
163
|
-
SpinniesManager.succeed(overallTaskSpinniesKey, {
|
|
164
|
-
text: statusStrings.SUCCESS(taskName, displayId),
|
|
165
|
-
});
|
|
166
|
-
clearInterval(pollInterval);
|
|
167
|
-
resolve(taskStatus);
|
|
168
|
-
}
|
|
169
|
-
else if (status === statusText.STATES.FAILURE) {
|
|
170
|
-
SpinniesManager.fail(overallTaskSpinniesKey, {
|
|
171
|
-
text: statusStrings.FAIL(taskName, displayId),
|
|
172
161
|
});
|
|
173
|
-
if (
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
uiLogger.log(`${statusStrings.SUBTASK_FAIL(failedSubtasks.length === 1
|
|
177
|
-
? getSubtaskName(failedSubtasks[0])
|
|
178
|
-
: failedSubtasks.length + ' components', displayId)}\n`);
|
|
179
|
-
uiLogger.log(lib.projectBuildAndDeploy.makePollTaskStatusFunc.errorSummary);
|
|
180
|
-
uiLine();
|
|
181
|
-
const displayErrors = failedSubtasks.filter(subtask => subtask?.standardError?.subCategory !==
|
|
182
|
-
PROJECT_ERROR_TYPES.SUBBUILD_FAILED &&
|
|
183
|
-
subtask?.standardError?.subCategory !==
|
|
184
|
-
PROJECT_ERROR_TYPES.SUBDEPLOY_FAILED);
|
|
185
|
-
displayErrors.forEach(subTask => {
|
|
186
|
-
uiLogger.log(`\n--- ${chalk.bold(getSubtaskName(subTask))} failed with the following error ---`);
|
|
187
|
-
uiLogger.error(subTask.errorMessage);
|
|
188
|
-
// Log nested errors
|
|
189
|
-
if (subTask.standardError && subTask.standardError.errors) {
|
|
190
|
-
uiLogger.log('');
|
|
191
|
-
subTask.standardError.errors.forEach(error => {
|
|
192
|
-
uiLogger.log(error.message);
|
|
193
|
-
});
|
|
194
|
-
}
|
|
162
|
+
if (status === statusText.STATES.SUCCESS) {
|
|
163
|
+
SpinniesManager.succeed(overallTaskSpinniesKey, {
|
|
164
|
+
text: statusStrings.SUCCESS(taskName, displayId),
|
|
195
165
|
});
|
|
166
|
+
clearInterval(pollInterval);
|
|
167
|
+
resolve(taskStatus);
|
|
168
|
+
}
|
|
169
|
+
else if (status === statusText.STATES.FAILURE) {
|
|
170
|
+
SpinniesManager.fail(overallTaskSpinniesKey, {
|
|
171
|
+
text: statusStrings.FAIL(taskName, displayId),
|
|
172
|
+
});
|
|
173
|
+
if (!silenceLogs) {
|
|
174
|
+
const failedSubtasks = subtasks.filter(subtask => subtask.status === 'FAILURE');
|
|
175
|
+
uiLine();
|
|
176
|
+
uiLogger.log(`${statusStrings.SUBTASK_FAIL(failedSubtasks.length === 1
|
|
177
|
+
? getSubtaskName(failedSubtasks[0])
|
|
178
|
+
: failedSubtasks.length + ' components', displayId)}\n`);
|
|
179
|
+
uiLogger.log(lib.projectBuildAndDeploy.makePollTaskStatusFunc.errorSummary);
|
|
180
|
+
uiLine();
|
|
181
|
+
const displayErrors = failedSubtasks.filter(subtask => subtask?.standardError?.subCategory !==
|
|
182
|
+
PROJECT_ERROR_TYPES.SUBBUILD_FAILED &&
|
|
183
|
+
subtask?.standardError?.subCategory !==
|
|
184
|
+
PROJECT_ERROR_TYPES.SUBDEPLOY_FAILED);
|
|
185
|
+
displayErrors.forEach(subTask => {
|
|
186
|
+
uiLogger.log(`\n--- ${chalk.bold(getSubtaskName(subTask))} failed with the following error ---`);
|
|
187
|
+
uiLogger.error(subTask.errorMessage);
|
|
188
|
+
// Log nested errors
|
|
189
|
+
if (subTask.standardError && subTask.standardError.errors) {
|
|
190
|
+
uiLogger.log('');
|
|
191
|
+
subTask.standardError.errors.forEach(error => {
|
|
192
|
+
uiLogger.log(error.message);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
clearInterval(pollInterval);
|
|
198
|
+
resolve(taskStatus);
|
|
199
|
+
}
|
|
200
|
+
else if (!subtasks.length) {
|
|
201
|
+
clearInterval(pollInterval);
|
|
202
|
+
resolve(taskStatus);
|
|
196
203
|
}
|
|
197
|
-
clearInterval(pollInterval);
|
|
198
|
-
resolve(taskStatus);
|
|
199
|
-
}
|
|
200
|
-
else if (!subtasks.length) {
|
|
201
|
-
clearInterval(pollInterval);
|
|
202
|
-
resolve(taskStatus);
|
|
203
204
|
}
|
|
204
205
|
}
|
|
206
|
+
catch (e) {
|
|
207
|
+
clearInterval(pollInterval);
|
|
208
|
+
reject(e);
|
|
209
|
+
}
|
|
205
210
|
}, DEFAULT_POLLING_DELAY);
|
|
206
211
|
});
|
|
207
212
|
};
|
package/lib/projects/upload.d.ts
CHANGED
package/lib/projects/upload.js
CHANGED
|
@@ -8,13 +8,11 @@ import { isTranslationError, translate, } from '@hubspot/project-parsing-lib/tra
|
|
|
8
8
|
import { projectContainsHsMetaFiles } from '@hubspot/project-parsing-lib/projects';
|
|
9
9
|
import SpinniesManager from '../ui/SpinniesManager.js';
|
|
10
10
|
import { uiAccountDescription } from '../ui/index.js';
|
|
11
|
-
import { logError } from '../errorHandlers/index.js';
|
|
12
11
|
import util from 'node:util';
|
|
13
12
|
import { lib } from '../../lang/en.js';
|
|
14
13
|
import { ensureProjectExists } from './ensureProjectExists.js';
|
|
15
14
|
import { uiLogger } from '../ui/logger.js';
|
|
16
15
|
import { isV2Project } from './platformVersion.js';
|
|
17
|
-
import { EXIT_CODES } from '../enums/exitCodes.js';
|
|
18
16
|
import ProjectValidationError from '../errors/ProjectValidationError.js';
|
|
19
17
|
import { walk } from '@hubspot/local-dev-lib/fs';
|
|
20
18
|
import { LEGACY_CONFIG_FILES } from '../constants.js';
|
|
@@ -46,57 +44,50 @@ async function uploadProjectFiles(accountId, projectName, filePath, uploadMessag
|
|
|
46
44
|
}
|
|
47
45
|
export async function handleProjectUpload({ accountId, projectConfig, projectDir, callbackFunc, profile, uploadMessage = '', forceCreate = false, isUploadCommand = false, sendIR = false, skipValidation = false, }) {
|
|
48
46
|
const srcDir = path.resolve(projectDir, projectConfig.srcDir);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
catch (e) {
|
|
53
|
-
logError(e);
|
|
54
|
-
process.exit(EXIT_CODES.ERROR);
|
|
55
|
-
}
|
|
56
|
-
try {
|
|
57
|
-
await validateNoHSMetaMismatch(srcDir, projectConfig);
|
|
58
|
-
}
|
|
59
|
-
catch (e) {
|
|
60
|
-
logError(e);
|
|
61
|
-
process.exit(EXIT_CODES.ERROR);
|
|
62
|
-
}
|
|
47
|
+
await validateSourceDirectory(srcDir, projectConfig, projectDir);
|
|
48
|
+
await validateNoHSMetaMismatch(srcDir, projectConfig);
|
|
63
49
|
const tempFile = tmp.fileSync({ postfix: '.zip' });
|
|
64
50
|
uiLogger.debug(lib.projectUpload.handleProjectUpload.compressing(tempFile.name));
|
|
65
51
|
const output = fs.createWriteStream(tempFile.name);
|
|
66
52
|
const archive = archiver('zip');
|
|
67
|
-
const result = new Promise(resolve => output.on('close', async function () {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
53
|
+
const result = new Promise((resolve, reject) => output.on('close', async function () {
|
|
54
|
+
try {
|
|
55
|
+
uiLogger.debug(lib.projectUpload.handleProjectUpload.compressed(archive.pointer()));
|
|
56
|
+
let intermediateRepresentation;
|
|
57
|
+
if (sendIR) {
|
|
58
|
+
try {
|
|
59
|
+
intermediateRepresentation = await handleTranslate({
|
|
60
|
+
projectDir,
|
|
61
|
+
projectConfig,
|
|
62
|
+
accountId,
|
|
63
|
+
skipValidation,
|
|
64
|
+
profile,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
return resolve({ uploadError: e });
|
|
69
|
+
}
|
|
79
70
|
}
|
|
80
|
-
|
|
81
|
-
|
|
71
|
+
const { projectExists } = await ensureProjectExists(accountId, projectConfig.name, {
|
|
72
|
+
forceCreate,
|
|
73
|
+
uploadCommand: isUploadCommand,
|
|
74
|
+
noLogs: true,
|
|
75
|
+
});
|
|
76
|
+
if (!projectExists) {
|
|
77
|
+
uiLogger.log(lib.projectUpload.handleProjectUpload.projectDoesNotExist(accountId));
|
|
78
|
+
return resolve({ projectNotFound: true });
|
|
79
|
+
}
|
|
80
|
+
const { buildId, error } = await uploadProjectFiles(accountId, projectConfig.name, tempFile.name, uploadMessage, projectConfig.platformVersion, intermediateRepresentation);
|
|
81
|
+
if (error) {
|
|
82
|
+
resolve({ uploadError: error });
|
|
83
|
+
}
|
|
84
|
+
else if (callbackFunc) {
|
|
85
|
+
const uploadResult = await callbackFunc(accountId, projectConfig, tempFile, buildId);
|
|
86
|
+
resolve({ result: uploadResult });
|
|
82
87
|
}
|
|
83
88
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
uploadCommand: isUploadCommand,
|
|
87
|
-
noLogs: true,
|
|
88
|
-
});
|
|
89
|
-
if (!projectExists) {
|
|
90
|
-
uiLogger.log(lib.projectUpload.handleProjectUpload.projectDoesNotExist(accountId));
|
|
91
|
-
process.exit(EXIT_CODES.SUCCESS);
|
|
92
|
-
}
|
|
93
|
-
const { buildId, error } = await uploadProjectFiles(accountId, projectConfig.name, tempFile.name, uploadMessage, projectConfig.platformVersion, intermediateRepresentation);
|
|
94
|
-
if (error) {
|
|
95
|
-
resolve({ uploadError: error });
|
|
96
|
-
}
|
|
97
|
-
else if (callbackFunc) {
|
|
98
|
-
const uploadResult = await callbackFunc(accountId, projectConfig, tempFile, buildId);
|
|
99
|
-
resolve({ result: uploadResult });
|
|
89
|
+
catch (e) {
|
|
90
|
+
reject(e);
|
|
100
91
|
}
|
|
101
92
|
}));
|
|
102
93
|
archive.pipe(output);
|
package/lib/projects/watch.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ProjectConfig } from '../../types/Projects.js';
|
|
2
2
|
type ProjectWatchHandlerFunction = (accountId: number, projectName: string, currentBuildId: number) => Promise<void> | void;
|
|
3
|
-
|
|
3
|
+
type WatchTerminationHandler = (error?: unknown) => void;
|
|
4
|
+
export declare function createWatcher(accountId: number, projectConfig: ProjectConfig, projectDir: string, handleBuildStatusFn: ProjectWatchHandlerFunction, handleUserInputFn: ProjectWatchHandlerFunction, handleWatchTerminationFn: WatchTerminationHandler): Promise<void>;
|
|
4
5
|
export {};
|
package/lib/projects/watch.js
CHANGED
|
@@ -18,6 +18,7 @@ const standbyQueue = [];
|
|
|
18
18
|
let currentBuildId;
|
|
19
19
|
let handleBuildStatus;
|
|
20
20
|
let handleUserInput;
|
|
21
|
+
let handleWatchTermination = () => { };
|
|
21
22
|
let timer;
|
|
22
23
|
async function processStandByQueue(accountId, projectName, platformVersion) {
|
|
23
24
|
queue.addAll(standbyQueue.map(({ filePath, remotePath, action }) => {
|
|
@@ -37,33 +38,39 @@ function debounceQueueBuild(accountId, projectName, platformVersion) {
|
|
|
37
38
|
clearTimeout(timer);
|
|
38
39
|
}
|
|
39
40
|
timer = setTimeout(async () => {
|
|
40
|
-
uiLogger.debug(commands.project.watch.debug.pause);
|
|
41
|
-
queue.pause();
|
|
42
|
-
await queue.onIdle();
|
|
43
41
|
try {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
42
|
+
uiLogger.debug(commands.project.watch.debug.pause);
|
|
43
|
+
queue.pause();
|
|
44
|
+
await queue.onIdle();
|
|
45
|
+
try {
|
|
46
|
+
await queueBuild(accountId, projectName, platformVersion);
|
|
47
|
+
uiLogger.debug(commands.project.watch.debug.buildStarted);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
if (isSpecifiedError(err, {
|
|
51
|
+
subCategory: PROJECT_ERROR_TYPES.MISSING_PROJECT_PROVISION,
|
|
52
|
+
})) {
|
|
53
|
+
uiLogger.log(commands.project.watch.logs.watchCancelledFromUi);
|
|
54
|
+
handleWatchTermination();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
logError(err, new ApiErrorContext({ accountId }));
|
|
59
|
+
}
|
|
60
|
+
return;
|
|
53
61
|
}
|
|
54
|
-
|
|
55
|
-
|
|
62
|
+
await handleBuildStatus(accountId, projectName, currentBuildId);
|
|
63
|
+
await createNewStagingBuild(accountId, projectName, platformVersion);
|
|
64
|
+
if (standbyQueue.length > 0) {
|
|
65
|
+
await processStandByQueue(accountId, projectName, platformVersion);
|
|
56
66
|
}
|
|
57
|
-
|
|
67
|
+
queue.start();
|
|
68
|
+
uiLogger.log(commands.project.watch.logs.resuming);
|
|
69
|
+
uiLogger.log(`\n> Press ${chalk.bold('q')} to quit watching\n`);
|
|
58
70
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (standbyQueue.length > 0) {
|
|
62
|
-
await processStandByQueue(accountId, projectName, platformVersion);
|
|
71
|
+
catch (err) {
|
|
72
|
+
handleWatchTermination(err);
|
|
63
73
|
}
|
|
64
|
-
queue.start();
|
|
65
|
-
uiLogger.log(commands.project.watch.logs.resuming);
|
|
66
|
-
uiLogger.log(`\n> Press ${chalk.bold('q')} to quit watching\n`);
|
|
67
74
|
}, 2000);
|
|
68
75
|
}
|
|
69
76
|
async function queueFileOrFolder(accountId, projectName, platformVersion, filePath, remotePath, action) {
|
|
@@ -111,7 +118,7 @@ async function createNewBuild(accountId, projectName, platformVersion) {
|
|
|
111
118
|
await cancelStagedBuild(accountId, projectName);
|
|
112
119
|
uiLogger.log(commands.project.watch.logs.previousStagingBuildCancelled);
|
|
113
120
|
}
|
|
114
|
-
|
|
121
|
+
throw err;
|
|
115
122
|
}
|
|
116
123
|
}
|
|
117
124
|
async function handleWatchEvent(accountId, projectName, platformVersion, projectSourceDir, filePath, action = 'upload') {
|
|
@@ -132,10 +139,11 @@ async function handleWatchEvent(accountId, projectName, platformVersion, project
|
|
|
132
139
|
await queueFileOrFolder(accountId, projectName, platformVersion, filePath, remotePath, action);
|
|
133
140
|
}
|
|
134
141
|
}
|
|
135
|
-
export async function createWatcher(accountId, projectConfig, projectDir, handleBuildStatusFn, handleUserInputFn) {
|
|
142
|
+
export async function createWatcher(accountId, projectConfig, projectDir, handleBuildStatusFn, handleUserInputFn, handleWatchTerminationFn) {
|
|
136
143
|
const projectSourceDir = path.join(projectDir, projectConfig.srcDir);
|
|
137
144
|
handleBuildStatus = handleBuildStatusFn;
|
|
138
145
|
handleUserInput = handleUserInputFn;
|
|
146
|
+
handleWatchTermination = handleWatchTerminationFn;
|
|
139
147
|
await createNewStagingBuild(accountId, projectConfig.name, projectConfig.platformVersion);
|
|
140
148
|
const watcher = chokidar.watch(projectSourceDir, {
|
|
141
149
|
ignoreInitial: true,
|
package/lib/serverlessLogs.js
CHANGED
|
@@ -9,7 +9,6 @@ import { outputLogs } from './ui/serverlessFunctionLogs.js';
|
|
|
9
9
|
import { logError, ApiErrorContext } from './errorHandlers/index.js';
|
|
10
10
|
import SpinniesManager from './ui/SpinniesManager.js';
|
|
11
11
|
import { handleExit, handleKeypress } from './process.js';
|
|
12
|
-
import { EXIT_CODES } from './enums/exitCodes.js';
|
|
13
12
|
import { lib } from '../lang/en.js';
|
|
14
13
|
const TAIL_DELAY = 5000;
|
|
15
14
|
function base64EncodeString(valueToEncode) {
|
|
@@ -19,19 +18,6 @@ function base64EncodeString(valueToEncode) {
|
|
|
19
18
|
const stringBuffer = Buffer.from(valueToEncode);
|
|
20
19
|
return encodeURIComponent(stringBuffer.toString('base64'));
|
|
21
20
|
}
|
|
22
|
-
function handleUserInput() {
|
|
23
|
-
const onTerminate = async () => {
|
|
24
|
-
SpinniesManager.remove('tailLogs');
|
|
25
|
-
SpinniesManager.remove('stopMessage');
|
|
26
|
-
process.exit(EXIT_CODES.SUCCESS);
|
|
27
|
-
};
|
|
28
|
-
handleExit(onTerminate);
|
|
29
|
-
handleKeypress(key => {
|
|
30
|
-
if ((key.ctrl && key.name == 'c') || key.name === 'q') {
|
|
31
|
-
onTerminate();
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
21
|
async function verifyAccessKeyAndUserAccess(accountId, scopeGroup) {
|
|
36
22
|
const accountConfig = getConfigAccountById(accountId);
|
|
37
23
|
if (!accountConfig) {
|
|
@@ -80,40 +66,60 @@ export async function tailLogs(accountId, name, fetchLatest, tailCall, compact =
|
|
|
80
66
|
}
|
|
81
67
|
}
|
|
82
68
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const { data } = await tailCall(after);
|
|
88
|
-
latestLog = data;
|
|
89
|
-
nextAfter = latestLog.paging.next.after;
|
|
69
|
+
return new Promise(resolve => {
|
|
70
|
+
function cleanup() {
|
|
71
|
+
SpinniesManager.remove('tailLogs');
|
|
72
|
+
SpinniesManager.remove('stopMessage');
|
|
90
73
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
74
|
+
let resolved = false;
|
|
75
|
+
const onTerminate = async () => {
|
|
76
|
+
if (resolved)
|
|
77
|
+
return;
|
|
78
|
+
resolved = true;
|
|
79
|
+
cleanup();
|
|
80
|
+
resolve();
|
|
81
|
+
};
|
|
82
|
+
handleExit(onTerminate);
|
|
83
|
+
handleKeypress(key => {
|
|
84
|
+
if ((key.ctrl && key.name == 'c') || key.name === 'q') {
|
|
85
|
+
onTerminate();
|
|
96
86
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
87
|
+
});
|
|
88
|
+
async function tail(after) {
|
|
89
|
+
let latestLog;
|
|
90
|
+
let nextAfter;
|
|
91
|
+
try {
|
|
92
|
+
const { data } = await tailCall(after);
|
|
93
|
+
latestLog = data;
|
|
94
|
+
nextAfter = latestLog.paging.next.after;
|
|
95
|
+
}
|
|
96
|
+
catch (e) {
|
|
97
|
+
if (isHubSpotHttpError(e) && e.status !== 404) {
|
|
98
|
+
logError(e, new ApiErrorContext({
|
|
99
|
+
accountId,
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
await onTerminate();
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (latestLog && latestLog.results.length) {
|
|
106
|
+
outputLogs(latestLog, {
|
|
107
|
+
compact,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
setTimeout(async () => {
|
|
111
|
+
await tail(nextAfter);
|
|
112
|
+
}, TAIL_DELAY);
|
|
103
113
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
text: `> Press ${chalk.bold('q')} to stop following`,
|
|
113
|
-
status: 'non-spinnable',
|
|
114
|
+
SpinniesManager.add('tailLogs', {
|
|
115
|
+
text: `Following logs for ${name}`,
|
|
116
|
+
});
|
|
117
|
+
SpinniesManager.add('stopMessage', {
|
|
118
|
+
text: `> Press ${chalk.bold('q')} to stop following`,
|
|
119
|
+
status: 'non-spinnable',
|
|
120
|
+
});
|
|
121
|
+
tail(initialAfter);
|
|
114
122
|
});
|
|
115
|
-
handleUserInput();
|
|
116
|
-
await tail(initialAfter);
|
|
117
123
|
}
|
|
118
124
|
export async function outputBuildLog(buildLogUrl) {
|
|
119
125
|
if (!buildLogUrl) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Tool } from '../../types.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { absoluteCurrentWorkingDirectory } from '../project/constants.js';
|
|
4
|
-
import { runCommandInDir } from '../../utils/
|
|
4
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
5
5
|
import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
6
6
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
7
7
|
import { addFlag } from '../../utils/command.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Tool } from '../../types.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { absoluteCurrentWorkingDirectory } from '../project/constants.js';
|
|
4
|
-
import { runCommandInDir } from '../../utils/
|
|
4
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
5
5
|
import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
6
6
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
7
7
|
import { addFlag } from '../../utils/command.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Tool } from '../../types.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { absoluteCurrentWorkingDirectory } from '../project/constants.js';
|
|
4
|
-
import { runCommandInDir } from '../../utils/
|
|
4
|
+
import { runCommandInDir } from '../../utils/command.js';
|
|
5
5
|
import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
6
6
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
7
7
|
import { addFlag } from '../../utils/command.js';
|