@hubspot/cli 4.2.1-beta.2 → 4.2.1-beta.4
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 +5 -2
- package/commands/accounts/clean.js +139 -0
- package/commands/accounts.js +2 -0
- package/commands/project/create.js +1 -1
- package/commands/project/dev.js +68 -111
- package/commands/project/download.js +10 -19
- package/commands/sandbox/delete.js +2 -2
- package/commands/sandbox.js +3 -2
- package/lang/en.lyaml +33 -57
- package/lib/DevServerManager.js +18 -67
- package/lib/LocalDevManager.js +235 -569
- package/lib/SpinniesManager.js +2 -82
- package/lib/projectStructure.js +1 -0
- package/lib/projects.js +45 -35
- package/lib/prompts/downloadProjectPrompt.js +1 -4
- package/lib/prompts/projectDevTargetAccountPrompt.js +20 -1
- package/lib/ui.js +9 -2
- package/package.json +5 -8
- package/lib/LocalDevManagerV2.js +0 -239
package/lib/LocalDevManager.js
CHANGED
|
@@ -1,40 +1,32 @@
|
|
|
1
|
-
const chokidar = require('chokidar');
|
|
2
1
|
const path = require('path');
|
|
3
|
-
const
|
|
2
|
+
const chokidar = require('chokidar');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
4
|
const { i18n } = require('./lang');
|
|
5
5
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
6
|
-
const {
|
|
7
|
-
isSpecifiedError,
|
|
8
|
-
} = require('@hubspot/cli-lib/errorHandlers/apiErrors');
|
|
9
6
|
const { handleKeypress } = require('@hubspot/cli-lib/lib/process');
|
|
10
7
|
const {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} = require('@hubspot/cli-lib/
|
|
14
|
-
const {
|
|
15
|
-
PROJECT_BUILD_TEXT,
|
|
16
|
-
PROJECT_DEPLOY_TEXT,
|
|
17
|
-
ERROR_TYPES,
|
|
18
|
-
} = require('@hubspot/cli-lib/lib/constants');
|
|
19
|
-
const { isAllowedExtension } = require('@hubspot/cli-lib/path');
|
|
20
|
-
const { shouldIgnoreFile } = require('@hubspot/cli-lib/ignoreRules');
|
|
21
|
-
const {
|
|
22
|
-
cancelStagedBuild,
|
|
23
|
-
uploadFileToBuild,
|
|
24
|
-
deleteFileFromBuild,
|
|
25
|
-
provisionBuild,
|
|
26
|
-
queueBuild,
|
|
27
|
-
} = require('@hubspot/cli-lib/api/dfs');
|
|
8
|
+
getAccountId,
|
|
9
|
+
getConfigDefaultAccount,
|
|
10
|
+
} = require('@hubspot/cli-lib/lib/config');
|
|
11
|
+
const { PROJECT_CONFIG_FILE } = require('@hubspot/cli-lib/lib/constants');
|
|
28
12
|
const SpinniesManager = require('./SpinniesManager');
|
|
29
13
|
const DevServerManager = require('./DevServerManager');
|
|
30
14
|
const { EXIT_CODES } = require('./enums/exitCodes');
|
|
31
|
-
const {
|
|
32
|
-
const {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
15
|
+
const { getProjectDetailUrl } = require('./projects');
|
|
16
|
+
const {
|
|
17
|
+
APP_COMPONENT_CONFIG,
|
|
18
|
+
COMPONENT_TYPES,
|
|
19
|
+
findProjectComponents,
|
|
20
|
+
getAppCardConfigs,
|
|
21
|
+
} = require('./projectStructure');
|
|
22
|
+
const {
|
|
23
|
+
UI_COLORS,
|
|
24
|
+
uiCommandReference,
|
|
25
|
+
uiAccountDescription,
|
|
26
|
+
uiBetaMessage,
|
|
27
|
+
uiLink,
|
|
28
|
+
uiLine,
|
|
29
|
+
} = require('./ui');
|
|
38
30
|
|
|
39
31
|
const WATCH_EVENTS = {
|
|
40
32
|
add: 'add',
|
|
@@ -43,30 +35,22 @@ const WATCH_EVENTS = {
|
|
|
43
35
|
unlinkDir: 'unlinkDir',
|
|
44
36
|
};
|
|
45
37
|
|
|
46
|
-
const
|
|
47
|
-
always: 'always',
|
|
48
|
-
manual: 'manual',
|
|
49
|
-
never: 'never',
|
|
50
|
-
};
|
|
38
|
+
const i18nKey = 'cli.lib.LocalDevManager';
|
|
51
39
|
|
|
52
40
|
class LocalDevManager {
|
|
53
41
|
constructor(options) {
|
|
54
42
|
this.targetAccountId = options.targetAccountId;
|
|
55
43
|
this.projectConfig = options.projectConfig;
|
|
56
44
|
this.projectDir = options.projectDir;
|
|
57
|
-
this.uploadPermission =
|
|
58
|
-
options.uploadPermission || UPLOAD_PERMISSIONS.always;
|
|
59
45
|
this.debug = options.debug || false;
|
|
46
|
+
this.deployedBuild = options.deployedBuild;
|
|
47
|
+
this.watcher = null;
|
|
48
|
+
this.uploadWarnings = {};
|
|
60
49
|
|
|
61
50
|
this.projectSourceDir = path.join(
|
|
62
51
|
this.projectDir,
|
|
63
52
|
this.projectConfig.srcDir
|
|
64
53
|
);
|
|
65
|
-
this.watcher = null;
|
|
66
|
-
this.uploadQueue = null;
|
|
67
|
-
this.standbyChanges = [];
|
|
68
|
-
this.debouncedBuild = null;
|
|
69
|
-
this.currentStagedBuildId = null;
|
|
70
54
|
|
|
71
55
|
if (!this.targetAccountId || !this.projectConfig || !this.projectDir) {
|
|
72
56
|
logger.log(i18n(`${i18nKey}.failedToInitialize`));
|
|
@@ -75,633 +59,315 @@ class LocalDevManager {
|
|
|
75
59
|
}
|
|
76
60
|
|
|
77
61
|
async start() {
|
|
62
|
+
SpinniesManager.stopAll();
|
|
78
63
|
SpinniesManager.init();
|
|
79
64
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
65
|
+
// Local dev currently relies on the existence of a deployed build in the target account
|
|
66
|
+
if (!this.deployedBuild) {
|
|
67
|
+
logger.error(
|
|
68
|
+
i18n(`${i18nKey}.noDeployedBuild`, {
|
|
69
|
+
accountIdentifier: uiAccountDescription(this.targetAccountId),
|
|
70
|
+
uploadCommand: this.getUploadCommand(),
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
logger.log();
|
|
74
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
75
|
+
}
|
|
84
76
|
|
|
85
|
-
|
|
77
|
+
const components = await findProjectComponents(this.projectSourceDir);
|
|
86
78
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
79
|
+
// The project is empty, there is nothing to run locally
|
|
80
|
+
if (!components.length) {
|
|
81
|
+
logger.error(i18n(`${i18nKey}.noComponents`));
|
|
82
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
91
83
|
}
|
|
92
84
|
|
|
93
|
-
|
|
94
|
-
|
|
85
|
+
const runnableComponents = components.filter(
|
|
86
|
+
component => component.runnable
|
|
87
|
+
);
|
|
95
88
|
|
|
96
|
-
|
|
97
|
-
|
|
89
|
+
// The project does not contain any components that support local development
|
|
90
|
+
if (!runnableComponents.length) {
|
|
91
|
+
logger.error(i18n(`${i18nKey}.noRunnableComponents`));
|
|
92
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const setupSucceeded = await this.devServerSetup(runnableComponents);
|
|
96
|
+
|
|
97
|
+
if (!setupSucceeded) {
|
|
98
|
+
process.exit(EXIT_CODES.ERROR);
|
|
99
|
+
} else if (!this.debug) {
|
|
100
|
+
console.clear();
|
|
101
|
+
}
|
|
98
102
|
|
|
99
|
-
|
|
103
|
+
uiBetaMessage(i18n(`${i18nKey}.betaMessage`));
|
|
104
|
+
logger.log();
|
|
105
|
+
logger.log(
|
|
106
|
+
chalk.hex(UI_COLORS.SORBET)(
|
|
107
|
+
i18n(`${i18nKey}.running`, {
|
|
108
|
+
accountIdentifier: uiAccountDescription(this.targetAccountId),
|
|
109
|
+
projectName: this.projectConfig.name,
|
|
110
|
+
})
|
|
111
|
+
)
|
|
112
|
+
);
|
|
113
|
+
logger.log(
|
|
114
|
+
uiLink(
|
|
115
|
+
i18n(`${i18nKey}.viewInHubSpotLink`),
|
|
116
|
+
getProjectDetailUrl(this.projectConfig.name, this.targetAccountId)
|
|
117
|
+
)
|
|
118
|
+
);
|
|
119
|
+
logger.log();
|
|
120
|
+
logger.log(i18n(`${i18nKey}.quitHelper`));
|
|
121
|
+
uiLine();
|
|
122
|
+
logger.log();
|
|
100
123
|
|
|
101
124
|
await this.devServerStart();
|
|
102
125
|
|
|
103
|
-
|
|
104
|
-
|
|
126
|
+
// Initialize project file watcher to detect configuration file changes
|
|
127
|
+
this.startWatching(runnableComponents);
|
|
105
128
|
|
|
106
129
|
this.updateKeypressListeners();
|
|
107
130
|
|
|
108
|
-
this.
|
|
131
|
+
this.monitorConsoleOutput();
|
|
132
|
+
|
|
133
|
+
// Verify that there are no mismatches between components in the local project
|
|
134
|
+
// and components in the deployed build of the project.
|
|
135
|
+
this.compareLocalProjectToDeployed(runnableComponents);
|
|
109
136
|
}
|
|
110
137
|
|
|
111
138
|
async stop() {
|
|
112
|
-
this.clearConsoleContent();
|
|
113
|
-
|
|
114
139
|
SpinniesManager.add('cleanupMessage', {
|
|
115
140
|
text: i18n(`${i18nKey}.exitingStart`),
|
|
116
141
|
});
|
|
117
142
|
|
|
118
143
|
await this.stopWatching();
|
|
119
|
-
await this.devServerCleanup();
|
|
120
|
-
|
|
121
|
-
let exitCode = EXIT_CODES.SUCCESS;
|
|
122
|
-
|
|
123
|
-
if (this.currentStagedBuildId) {
|
|
124
|
-
try {
|
|
125
|
-
await cancelStagedBuild(this.targetAccountId, this.projectConfig.name);
|
|
126
|
-
} catch (err) {
|
|
127
|
-
if (
|
|
128
|
-
!isSpecifiedError(err, {
|
|
129
|
-
subCategory: ERROR_TYPES.BUILD_NOT_IN_PROGRESS,
|
|
130
|
-
})
|
|
131
|
-
) {
|
|
132
|
-
logApiErrorInstance(
|
|
133
|
-
err,
|
|
134
|
-
new ApiErrorContext({
|
|
135
|
-
accountId: this.targetAccountId,
|
|
136
|
-
projectName: this.projectConfig.name,
|
|
137
|
-
})
|
|
138
|
-
);
|
|
139
|
-
exitCode = EXIT_CODES.ERROR;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
144
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
});
|
|
148
|
-
} else {
|
|
145
|
+
const cleanupSucceeded = await this.devServerCleanup();
|
|
146
|
+
|
|
147
|
+
if (!cleanupSucceeded) {
|
|
149
148
|
SpinniesManager.fail('cleanupMessage', {
|
|
150
149
|
text: i18n(`${i18nKey}.exitingFail`),
|
|
151
150
|
});
|
|
151
|
+
process.exit(EXIT_CODES.ERROR);
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
updateConsoleHeader() {
|
|
158
|
-
SpinniesManager.addOrUpdate('devModeRunning', {
|
|
159
|
-
text: i18n(`${i18nKey}.header.running`, {
|
|
160
|
-
accountIdentifier: uiAccountDescription(this.targetAccountId),
|
|
161
|
-
projectName: this.projectConfig.name,
|
|
162
|
-
}),
|
|
163
|
-
isParent: true,
|
|
164
|
-
category: 'header',
|
|
165
|
-
});
|
|
166
|
-
SpinniesManager.addOrUpdate('devModeStatus', {
|
|
167
|
-
text: i18n(`${i18nKey}.header.status.clean`),
|
|
168
|
-
status: 'non-spinnable',
|
|
169
|
-
indent: 1,
|
|
170
|
-
category: 'header',
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
const viewText = DevServerManager.initialized
|
|
174
|
-
? uiLink(
|
|
175
|
-
i18n(`${i18nKey}.header.viewInHubSpotLink`),
|
|
176
|
-
DevServerManager.generateURL(`hs/project`),
|
|
177
|
-
{
|
|
178
|
-
inSpinnies: true,
|
|
179
|
-
}
|
|
180
|
-
)
|
|
181
|
-
: ' ';
|
|
182
|
-
|
|
183
|
-
SpinniesManager.addOrUpdate('viewInHubSpotLink', {
|
|
184
|
-
text: viewText,
|
|
185
|
-
status: 'non-spinnable',
|
|
186
|
-
indent: 1,
|
|
187
|
-
category: 'header',
|
|
188
|
-
});
|
|
189
|
-
SpinniesManager.addOrUpdate('spacer-1', {
|
|
190
|
-
text: ' ',
|
|
191
|
-
status: 'non-spinnable',
|
|
192
|
-
category: 'header',
|
|
154
|
+
SpinniesManager.succeed('cleanupMessage', {
|
|
155
|
+
text: i18n(`${i18nKey}.exitingSucceed`),
|
|
193
156
|
});
|
|
194
|
-
|
|
195
|
-
text: i18n(`${i18nKey}.header.quitHelper`),
|
|
196
|
-
status: 'non-spinnable',
|
|
197
|
-
indent: 1,
|
|
198
|
-
category: 'header',
|
|
199
|
-
});
|
|
200
|
-
SpinniesManager.addOrUpdate('lineSeparator', {
|
|
201
|
-
text: '-'.repeat(50),
|
|
202
|
-
status: 'non-spinnable',
|
|
203
|
-
noIndent: true,
|
|
204
|
-
category: 'header',
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
clearConsoleContent() {
|
|
209
|
-
SpinniesManager.removeAll({ preserveCategory: 'header' });
|
|
157
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
210
158
|
}
|
|
211
159
|
|
|
212
160
|
updateKeypressListeners() {
|
|
213
161
|
handleKeypress(async key => {
|
|
214
162
|
if ((key.ctrl && key.name === 'c') || key.name === 'q') {
|
|
215
163
|
this.stop();
|
|
216
|
-
} else if (
|
|
217
|
-
(key.name === 'y' || key.name === 'n') &&
|
|
218
|
-
this.uploadPermission === UPLOAD_PERMISSIONS.manual &&
|
|
219
|
-
this.hasAnyUnsupportedStandbyChanges()
|
|
220
|
-
) {
|
|
221
|
-
SpinniesManager.remove('manualUploadRequired');
|
|
222
|
-
SpinniesManager.remove('manualUploadExplanation1');
|
|
223
|
-
SpinniesManager.remove('manualUploadExplanation2');
|
|
224
|
-
SpinniesManager.remove('manualUploadPrompt');
|
|
225
|
-
|
|
226
|
-
if (key.name === 'y') {
|
|
227
|
-
SpinniesManager.add(null, {
|
|
228
|
-
text: i18n(`${i18nKey}.upload.manualUploadConfirmed`),
|
|
229
|
-
status: 'succeed',
|
|
230
|
-
succeedColor: 'white',
|
|
231
|
-
noIndent: true,
|
|
232
|
-
});
|
|
233
|
-
this.updateDevModeStatus('manualUpload');
|
|
234
|
-
await this.createNewStagingBuild();
|
|
235
|
-
this.flushStandbyChanges();
|
|
236
|
-
await this.queueBuild();
|
|
237
|
-
} else if (key.name === 'n') {
|
|
238
|
-
SpinniesManager.add(null, {
|
|
239
|
-
text: i18n(`${i18nKey}.upload.manualUploadSkipped`),
|
|
240
|
-
status: 'fail',
|
|
241
|
-
failColor: 'white',
|
|
242
|
-
noIndent: true,
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
164
|
}
|
|
246
165
|
});
|
|
247
166
|
}
|
|
248
167
|
|
|
249
|
-
|
|
250
|
-
const
|
|
251
|
-
const failedSubTasks = subTasks.filter(task => task.status === 'FAILURE');
|
|
252
|
-
|
|
253
|
-
if (failedSubTasks.length) {
|
|
254
|
-
this.updateDevModeStatus('buildError');
|
|
255
|
-
|
|
256
|
-
failedSubTasks.forEach(failedSubTask => {
|
|
257
|
-
SpinniesManager.add(null, {
|
|
258
|
-
text: failedSubTask.errorMessage,
|
|
259
|
-
status: 'fail',
|
|
260
|
-
failColor: 'white',
|
|
261
|
-
indent: 1,
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
logDeployError(deployStatus = {}) {
|
|
268
|
-
const subTasks = deployStatus[PROJECT_DEPLOY_TEXT.SUBTASK_KEY] || [];
|
|
269
|
-
const failedSubTasks = subTasks.filter(task => task.status === 'FAILURE');
|
|
270
|
-
|
|
271
|
-
if (failedSubTasks.length) {
|
|
272
|
-
this.updateDevModeStatus('deployError');
|
|
168
|
+
getUploadCommand() {
|
|
169
|
+
const currentDefaultAccount = getConfigDefaultAccount();
|
|
273
170
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
indent: 1,
|
|
280
|
-
});
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
updateDevModeStatus(langKey) {
|
|
286
|
-
SpinniesManager.update('devModeStatus', {
|
|
287
|
-
text: i18n(`${i18nKey}.header.status.${langKey}`),
|
|
288
|
-
status: 'non-spinnable',
|
|
289
|
-
noIndent: true,
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
async pauseUploadQueue() {
|
|
294
|
-
this.uploadQueue.pause();
|
|
295
|
-
await this.uploadQueue.onIdle();
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
hasAnyUnsupportedStandbyChanges() {
|
|
299
|
-
return this.standbyChanges.some(({ supported }) => !supported);
|
|
171
|
+
return this.targetAccountId !== getAccountId(currentDefaultAccount)
|
|
172
|
+
? uiCommandReference(
|
|
173
|
+
`hs project upload --account=${this.targetAccountId}`
|
|
174
|
+
)
|
|
175
|
+
: uiCommandReference('hs project upload');
|
|
300
176
|
}
|
|
301
177
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
178
|
+
logUploadWarning(reason) {
|
|
179
|
+
const warning = reason || i18n(`${i18nKey}.uploadWarning.defaultWarning`);
|
|
180
|
+
|
|
181
|
+
// Avoid logging the warning to the console if it is currently the most
|
|
182
|
+
// recently logged warning. We do not want to spam the console with the same message.
|
|
183
|
+
if (!this.uploadWarnings[warning]) {
|
|
184
|
+
logger.log();
|
|
185
|
+
logger.warn(i18n(`${i18nKey}.uploadWarning.header`, { warning }));
|
|
186
|
+
logger.log(
|
|
187
|
+
i18n(`${i18nKey}.uploadWarning.stopDev`, {
|
|
188
|
+
command: uiCommandReference('hs project dev'),
|
|
189
|
+
})
|
|
190
|
+
);
|
|
191
|
+
logger.log(
|
|
192
|
+
i18n(`${i18nKey}.uploadWarning.runUpload`, {
|
|
193
|
+
command: this.getUploadCommand(),
|
|
194
|
+
})
|
|
195
|
+
);
|
|
196
|
+
logger.log(
|
|
197
|
+
i18n(`${i18nKey}.uploadWarning.restartDev`, {
|
|
198
|
+
command: uiCommandReference('hs project dev'),
|
|
199
|
+
})
|
|
308
200
|
);
|
|
309
|
-
this.currentStagedBuildId = buildId;
|
|
310
|
-
} catch (err) {
|
|
311
|
-
logger.debug(err);
|
|
312
|
-
if (isSpecifiedError(err, { subCategory: ERROR_TYPES.PROJECT_LOCKED })) {
|
|
313
|
-
await cancelStagedBuild(this.targetAccountId, this.projectConfig.name);
|
|
314
|
-
SpinniesManager.add(null, {
|
|
315
|
-
text: i18n(`${i18nKey}.previousStagingBuildCancelled`),
|
|
316
|
-
status: 'non-spinnable',
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
this.stop();
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
201
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
await this.createNewStagingBuild();
|
|
202
|
+
this.mostRecentUploadWarning = warning;
|
|
203
|
+
this.uploadWarnings[warning] = true;
|
|
326
204
|
}
|
|
327
|
-
|
|
328
|
-
this.watcher.on('add', async filePath => {
|
|
329
|
-
this.handleWatchEvent(filePath, WATCH_EVENTS.add);
|
|
330
|
-
});
|
|
331
|
-
this.watcher.on('change', async filePath => {
|
|
332
|
-
this.handleWatchEvent(filePath, WATCH_EVENTS.change);
|
|
333
|
-
});
|
|
334
|
-
this.watcher.on('unlink', async filePath => {
|
|
335
|
-
this.handleWatchEvent(filePath, WATCH_EVENTS.unlink);
|
|
336
|
-
});
|
|
337
|
-
this.watcher.on('unlinkDir', async filePath => {
|
|
338
|
-
this.handleWatchEvent(filePath, WATCH_EVENTS.unlinkDir);
|
|
339
|
-
});
|
|
340
205
|
}
|
|
341
206
|
|
|
342
|
-
|
|
343
|
-
const
|
|
344
|
-
event,
|
|
345
|
-
filePath,
|
|
346
|
-
remotePath: path.relative(this.projectSourceDir, filePath),
|
|
347
|
-
};
|
|
207
|
+
monitorConsoleOutput() {
|
|
208
|
+
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
348
209
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
this.addChangeToStandbyQueue({ ...changeInfo, supported: false });
|
|
210
|
+
process.stdout.write = function(chunk, encoding, callback) {
|
|
211
|
+
// Reset the most recently logged warning
|
|
212
|
+
if (
|
|
213
|
+
this.mostRecentUploadWarning &&
|
|
214
|
+
this.uploadWarnings[this.mostRecentUploadWarning]
|
|
215
|
+
) {
|
|
216
|
+
delete this.uploadWarnings[this.mostRecentUploadWarning];
|
|
217
|
+
}
|
|
359
218
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
}
|
|
219
|
+
return originalStdoutWrite(chunk, encoding, callback);
|
|
220
|
+
}.bind(this);
|
|
363
221
|
}
|
|
364
222
|
|
|
365
|
-
|
|
366
|
-
const
|
|
223
|
+
compareLocalProjectToDeployed(runnableComponents) {
|
|
224
|
+
const deployedComponentNames = this.deployedBuild.subbuildStatuses.map(
|
|
225
|
+
subbuildStatus => subbuildStatus.buildName
|
|
226
|
+
);
|
|
367
227
|
|
|
368
|
-
|
|
369
|
-
this.updateDevModeStatus('noUploadsAllowed');
|
|
228
|
+
let missingComponents = [];
|
|
370
229
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
}),
|
|
375
|
-
status: 'fail',
|
|
376
|
-
failColor: 'white',
|
|
377
|
-
noIndent: true,
|
|
378
|
-
});
|
|
379
|
-
} else {
|
|
380
|
-
this.updateDevModeStatus('manualUploadRequired');
|
|
230
|
+
runnableComponents.forEach(({ type, config, path }) => {
|
|
231
|
+
if (type === COMPONENT_TYPES.app) {
|
|
232
|
+
const cardConfigs = getAppCardConfigs(config, path);
|
|
381
233
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
234
|
+
if (!deployedComponentNames.includes(config.name)) {
|
|
235
|
+
missingComponents.push(
|
|
236
|
+
`${i18n(`${i18nKey}.uploadWarning.appLabel`)} ${config.name}`
|
|
237
|
+
);
|
|
238
|
+
}
|
|
386
239
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
SpinniesManager.add('manualUploadExplanation2', {
|
|
400
|
-
text: i18n(`${i18nKey}.upload.manualUploadExplanation2`),
|
|
401
|
-
status: 'non-spinnable',
|
|
402
|
-
indent: 1,
|
|
403
|
-
});
|
|
404
|
-
SpinniesManager.add('manualUploadPrompt', {
|
|
405
|
-
text: i18n(`${i18nKey}.upload.manualUploadPrompt`),
|
|
406
|
-
status: 'non-spinnable',
|
|
407
|
-
indent: 1,
|
|
240
|
+
cardConfigs.forEach(cardConfig => {
|
|
241
|
+
if (
|
|
242
|
+
cardConfig.data &&
|
|
243
|
+
cardConfig.data.title &&
|
|
244
|
+
!deployedComponentNames.includes(cardConfig.data.title)
|
|
245
|
+
) {
|
|
246
|
+
missingComponents.push(
|
|
247
|
+
`${i18n(`${i18nKey}.uploadWarning.uiExtensionLabel`)} ${
|
|
248
|
+
cardConfig.data.title
|
|
249
|
+
}`
|
|
250
|
+
);
|
|
251
|
+
}
|
|
408
252
|
});
|
|
409
253
|
}
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
if (missingComponents.length) {
|
|
257
|
+
this.logUploadWarning(
|
|
258
|
+
i18n(`${i18nKey}.uploadWarning.missingComponents`, {
|
|
259
|
+
missingComponents: missingComponents.join(', '),
|
|
260
|
+
})
|
|
261
|
+
);
|
|
410
262
|
}
|
|
411
263
|
}
|
|
412
264
|
|
|
413
|
-
|
|
414
|
-
|
|
265
|
+
startWatching(runnableComponents) {
|
|
266
|
+
this.watcher = chokidar.watch(this.projectDir, {
|
|
267
|
+
ignoreInitial: true,
|
|
268
|
+
});
|
|
415
269
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}),
|
|
422
|
-
status: 'non-spinnable',
|
|
423
|
-
});
|
|
424
|
-
return false;
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
if (shouldIgnoreFile(filePath, true)) {
|
|
428
|
-
SpinniesManager.add(null, {
|
|
429
|
-
text: i18n(`${i18nKey}.upload.fileIgnored`, {
|
|
430
|
-
filePath,
|
|
431
|
-
}),
|
|
432
|
-
status: 'non-spinnable',
|
|
270
|
+
const configPaths = runnableComponents
|
|
271
|
+
.filter(({ type }) => type === COMPONENT_TYPES.app)
|
|
272
|
+
.map(component => {
|
|
273
|
+
const appConfigPath = path.join(component.path, APP_COMPONENT_CONFIG);
|
|
274
|
+
return appConfigPath;
|
|
433
275
|
});
|
|
434
|
-
return false;
|
|
435
|
-
}
|
|
436
276
|
|
|
437
|
-
const
|
|
438
|
-
|
|
439
|
-
);
|
|
277
|
+
const projectConfigPath = path.join(this.projectDir, PROJECT_CONFIG_FILE);
|
|
278
|
+
configPaths.push(projectConfigPath);
|
|
440
279
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
this.
|
|
446
|
-
}
|
|
447
|
-
|
|
280
|
+
this.watcher.on('add', filePath => {
|
|
281
|
+
this.handleWatchEvent(filePath, WATCH_EVENTS.add, configPaths);
|
|
282
|
+
});
|
|
283
|
+
this.watcher.on('change', filePath => {
|
|
284
|
+
this.handleWatchEvent(filePath, WATCH_EVENTS.change, configPaths);
|
|
285
|
+
});
|
|
286
|
+
this.watcher.on('unlink', filePath => {
|
|
287
|
+
this.handleWatchEvent(filePath, WATCH_EVENTS.unlink, configPaths);
|
|
288
|
+
});
|
|
289
|
+
this.watcher.on('unlinkDir', filePath => {
|
|
290
|
+
this.handleWatchEvent(filePath, WATCH_EVENTS.unlinkDir, configPaths);
|
|
291
|
+
});
|
|
448
292
|
}
|
|
449
293
|
|
|
450
|
-
async
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
try {
|
|
454
|
-
if (event === WATCH_EVENTS.add || event === WATCH_EVENTS.change) {
|
|
455
|
-
const { name: spinnerName } = SpinniesManager.add(null, {
|
|
456
|
-
text: i18n(`${i18nKey}.upload.uploadingAddChange`, {
|
|
457
|
-
filePath: remotePath,
|
|
458
|
-
}),
|
|
459
|
-
status: 'non-spinnable',
|
|
460
|
-
});
|
|
461
|
-
await uploadFileToBuild(
|
|
462
|
-
this.targetAccountId,
|
|
463
|
-
this.projectConfig.name,
|
|
464
|
-
filePath,
|
|
465
|
-
remotePath
|
|
466
|
-
);
|
|
467
|
-
SpinniesManager.update(spinnerName, {
|
|
468
|
-
text: i18n(`${i18nKey}.upload.uploadedAddChange`, {
|
|
469
|
-
filePath: remotePath,
|
|
470
|
-
}),
|
|
471
|
-
status: 'non-spinnable',
|
|
472
|
-
});
|
|
473
|
-
} else if (
|
|
474
|
-
event === WATCH_EVENTS.unlink ||
|
|
475
|
-
event === WATCH_EVENTS.unlinkDir
|
|
476
|
-
) {
|
|
477
|
-
const { name: spinnerName } = SpinniesManager.add(null, {
|
|
478
|
-
text: i18n(`${i18nKey}.upload.uploadingRemoveChange`, {
|
|
479
|
-
filePath: remotePath,
|
|
480
|
-
}),
|
|
481
|
-
status: 'non-spinnable',
|
|
482
|
-
});
|
|
483
|
-
const path =
|
|
484
|
-
event === WATCH_EVENTS.unlinkDir ? `${remotePath}/` : remotePath;
|
|
485
|
-
await deleteFileFromBuild(
|
|
486
|
-
this.targetAccountId,
|
|
487
|
-
this.projectConfig.name,
|
|
488
|
-
path
|
|
489
|
-
);
|
|
490
|
-
SpinniesManager.update(spinnerName, {
|
|
491
|
-
text: i18n(`${i18nKey}.upload.uploadedRemoveChange`, {
|
|
492
|
-
filePath: remotePath,
|
|
493
|
-
}),
|
|
494
|
-
status: 'non-spinnable',
|
|
495
|
-
});
|
|
496
|
-
}
|
|
497
|
-
} catch (err) {
|
|
498
|
-
logger.debug(err);
|
|
499
|
-
}
|
|
294
|
+
async stopWatching() {
|
|
295
|
+
await this.watcher.close();
|
|
500
296
|
}
|
|
501
297
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
this.
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
if (this.debouncedBuild) {
|
|
510
|
-
clearTimeout(this.debouncedBuild);
|
|
298
|
+
handleWatchEvent(filePath, event, configPaths) {
|
|
299
|
+
if (configPaths.includes(filePath)) {
|
|
300
|
+
this.logUploadWarning();
|
|
301
|
+
} else {
|
|
302
|
+
this.devServerFileChange(filePath, event);
|
|
511
303
|
}
|
|
512
|
-
|
|
513
|
-
const debounceWaitTime =
|
|
514
|
-
event === WATCH_EVENTS.add
|
|
515
|
-
? BUILD_DEBOUNCE_TIME_LONG
|
|
516
|
-
: BUILD_DEBOUNCE_TIME_SHORT;
|
|
517
|
-
|
|
518
|
-
this.debouncedBuild = setTimeout(
|
|
519
|
-
this.queueBuild.bind(this),
|
|
520
|
-
debounceWaitTime
|
|
521
|
-
);
|
|
522
304
|
}
|
|
523
305
|
|
|
524
|
-
async
|
|
525
|
-
SpinniesManager.add(null, { text: ' ', status: 'non-spinnable' });
|
|
526
|
-
|
|
527
|
-
const { name: spinnerName } = SpinniesManager.add(null, {
|
|
528
|
-
text: i18n(`${i18nKey}.upload.uploadingChanges`, {
|
|
529
|
-
accountIdentifier: uiAccountDescription(this.targetAccountId),
|
|
530
|
-
buildId: this.currentStagedBuildId,
|
|
531
|
-
}),
|
|
532
|
-
noIndent: true,
|
|
533
|
-
});
|
|
534
|
-
|
|
535
|
-
await this.pauseUploadQueue();
|
|
536
|
-
|
|
537
|
-
let queueBuildError;
|
|
538
|
-
|
|
306
|
+
async devServerSetup(components) {
|
|
539
307
|
try {
|
|
540
|
-
await
|
|
541
|
-
|
|
542
|
-
this.
|
|
543
|
-
this.
|
|
544
|
-
);
|
|
545
|
-
} catch (err) {
|
|
546
|
-
queueBuildError = err;
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
if (queueBuildError) {
|
|
550
|
-
this.updateDevModeStatus('buildError');
|
|
551
|
-
|
|
552
|
-
logger.debug(queueBuildError);
|
|
553
|
-
|
|
554
|
-
SpinniesManager.fail(spinnerName, {
|
|
555
|
-
text: i18n(`${i18nKey}.upload.uploadedChangesFailed`, {
|
|
556
|
-
accountIdentifier: uiAccountDescription(this.targetAccountId),
|
|
557
|
-
buildId: this.currentStagedBuildId,
|
|
558
|
-
}),
|
|
559
|
-
failColor: 'white',
|
|
560
|
-
noIndent: true,
|
|
308
|
+
await DevServerManager.setup({
|
|
309
|
+
components,
|
|
310
|
+
debug: this.debug,
|
|
311
|
+
onUploadRequired: this.logUploadWarning.bind(this),
|
|
561
312
|
});
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
})
|
|
567
|
-
) {
|
|
568
|
-
SpinniesManager.add(null, {
|
|
569
|
-
text: i18n(`${i18nKey}.cancelledFromUI`),
|
|
570
|
-
status: 'non-spinnable',
|
|
571
|
-
indent: 1,
|
|
572
|
-
});
|
|
573
|
-
this.stop();
|
|
574
|
-
} else if (
|
|
575
|
-
queueBuildError &&
|
|
576
|
-
queueBuildError.error &&
|
|
577
|
-
queueBuildError.error.message
|
|
578
|
-
) {
|
|
579
|
-
SpinniesManager.add(null, {
|
|
580
|
-
text: queueBuildError.error.message,
|
|
581
|
-
status: 'non-spinnable',
|
|
582
|
-
indent: 1,
|
|
583
|
-
});
|
|
584
|
-
}
|
|
585
|
-
} else {
|
|
586
|
-
const result = await pollProjectBuildAndDeploy(
|
|
587
|
-
this.targetAccountId,
|
|
588
|
-
this.projectConfig,
|
|
589
|
-
null,
|
|
590
|
-
this.currentStagedBuildId,
|
|
591
|
-
true
|
|
592
|
-
);
|
|
593
|
-
|
|
594
|
-
if (result.succeeded) {
|
|
595
|
-
this.updateDevModeStatus('clean');
|
|
596
|
-
|
|
597
|
-
SpinniesManager.succeed(spinnerName, {
|
|
598
|
-
text: i18n(`${i18nKey}.upload.uploadedChangesSucceeded`, {
|
|
599
|
-
accountIdentifier: uiAccountDescription(this.targetAccountId),
|
|
600
|
-
buildId: result.buildId,
|
|
601
|
-
}),
|
|
602
|
-
succeedColor: 'white',
|
|
603
|
-
noIndent: true,
|
|
604
|
-
});
|
|
605
|
-
} else {
|
|
606
|
-
SpinniesManager.fail(spinnerName, {
|
|
607
|
-
text: i18n(`${i18nKey}.upload.uploadedChangesFailed`, {
|
|
608
|
-
accountIdentifier: uiAccountDescription(this.targetAccountId),
|
|
609
|
-
buildId: result.buildId,
|
|
610
|
-
}),
|
|
611
|
-
failColor: 'white',
|
|
612
|
-
noIndent: true,
|
|
613
|
-
});
|
|
614
|
-
|
|
615
|
-
if (result.buildResult.status === 'FAILURE') {
|
|
616
|
-
this.logBuildError(result.buildResult);
|
|
617
|
-
} else if (result.deployResult.status === 'FAILURE') {
|
|
618
|
-
this.logDeployError(result.deployResult);
|
|
619
|
-
}
|
|
313
|
+
return true;
|
|
314
|
+
} catch (e) {
|
|
315
|
+
if (this.debug) {
|
|
316
|
+
logger.error(e);
|
|
620
317
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
SpinniesManager.removeAll({ targetCategory: 'projectPollStatus' });
|
|
624
|
-
|
|
625
|
-
if (
|
|
626
|
-
!queueBuildError &&
|
|
627
|
-
this.uploadPermission === UPLOAD_PERMISSIONS.always
|
|
628
|
-
) {
|
|
629
|
-
await this.createNewStagingBuild();
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
this.uploadQueue.start();
|
|
633
|
-
|
|
634
|
-
if (this.hasAnyUnsupportedStandbyChanges()) {
|
|
635
|
-
this.flushStandbyChanges();
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
flushStandbyChanges() {
|
|
640
|
-
if (this.standbyChanges.length) {
|
|
641
|
-
this.uploadQueue.addAll(
|
|
642
|
-
this.standbyChanges.map(changeInfo => {
|
|
643
|
-
return async () => {
|
|
644
|
-
if (
|
|
645
|
-
this.uploadPermission === UPLOAD_PERMISSIONS.always &&
|
|
646
|
-
!this.uploadQueue.isPaused
|
|
647
|
-
) {
|
|
648
|
-
this.debounceQueueBuild(changeInfo);
|
|
649
|
-
}
|
|
650
|
-
await this.sendChanges(changeInfo);
|
|
651
|
-
};
|
|
652
|
-
})
|
|
318
|
+
logger.error(
|
|
319
|
+
i18n(`${i18nKey}.devServer.setupError`, { message: e.message })
|
|
653
320
|
);
|
|
654
|
-
|
|
321
|
+
return false;
|
|
655
322
|
}
|
|
656
323
|
}
|
|
657
324
|
|
|
658
|
-
async stopWatching() {
|
|
659
|
-
await this.watcher.close();
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
handleServerLog(serverKey, ...args) {
|
|
663
|
-
SpinniesManager.add(null, {
|
|
664
|
-
text: `${args.join('')}`,
|
|
665
|
-
status: 'non-spinnable',
|
|
666
|
-
});
|
|
667
|
-
}
|
|
668
|
-
|
|
669
325
|
async devServerStart() {
|
|
670
326
|
try {
|
|
671
|
-
// Set this to true manually for now
|
|
672
|
-
DevServerManager.initialized = true;
|
|
673
|
-
|
|
674
327
|
await DevServerManager.start({
|
|
675
328
|
accountId: this.targetAccountId,
|
|
676
|
-
debug: this.debug,
|
|
677
|
-
spinniesLogger: this.handleServerLog,
|
|
678
329
|
projectConfig: this.projectConfig,
|
|
679
|
-
projectSourceDir: this.projectSourceDir,
|
|
680
330
|
});
|
|
681
331
|
} catch (e) {
|
|
682
332
|
if (this.debug) {
|
|
683
333
|
logger.error(e);
|
|
684
334
|
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
335
|
+
logger.error(
|
|
336
|
+
i18n(`${i18nKey}.devServer.startError`, { message: e.message })
|
|
337
|
+
);
|
|
338
|
+
process.exit(EXIT_CODES.ERROR);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
devServerFileChange(filePath, event) {
|
|
343
|
+
try {
|
|
344
|
+
DevServerManager.fileChange({ filePath, event });
|
|
345
|
+
} catch (e) {
|
|
346
|
+
if (this.debug) {
|
|
347
|
+
logger.error(e);
|
|
348
|
+
}
|
|
349
|
+
logger.error(
|
|
350
|
+
i18n(`${i18nKey}.devServer.fileChangeError`, {
|
|
351
|
+
message: e.message,
|
|
352
|
+
})
|
|
353
|
+
);
|
|
689
354
|
}
|
|
690
355
|
}
|
|
691
356
|
|
|
692
357
|
async devServerCleanup() {
|
|
693
358
|
try {
|
|
694
359
|
await DevServerManager.cleanup();
|
|
360
|
+
return true;
|
|
695
361
|
} catch (e) {
|
|
696
362
|
if (this.debug) {
|
|
697
363
|
logger.error(e);
|
|
698
364
|
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
365
|
+
logger.error(
|
|
366
|
+
i18n(`${i18nKey}.devServer.cleanupError`, { message: e.message })
|
|
367
|
+
);
|
|
368
|
+
return false;
|
|
703
369
|
}
|
|
704
370
|
}
|
|
705
371
|
}
|
|
706
372
|
|
|
707
|
-
module.exports =
|
|
373
|
+
module.exports = LocalDevManager;
|