@hubspot/cli 4.2.1-beta.2 → 4.2.1-beta.3
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/accounts/clean.js +139 -0
- package/commands/accounts.js +2 -0
- package/commands/project/dev.js +68 -105
- 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 -56
- package/lib/DevServerManager.js +18 -67
- package/lib/LocalDevManager.js +240 -569
- package/lib/SpinniesManager.js +2 -82
- package/lib/projectStructure.js +1 -0
- package/lib/projects.js +38 -19
- package/lib/prompts/downloadProjectPrompt.js +1 -4
- package/lib/prompts/projectDevTargetAccountPrompt.js +15 -0
- 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,320 @@ 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.log();
|
|
68
|
+
logger.error(
|
|
69
|
+
i18n(`${i18nKey}.noDeployedBuild`, {
|
|
70
|
+
accountIdentifier: uiAccountDescription(this.targetAccountId),
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
74
|
+
}
|
|
84
75
|
|
|
85
|
-
|
|
76
|
+
const components = await findProjectComponents(this.projectSourceDir);
|
|
86
77
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
});
|
|
78
|
+
// The project is empty, there is nothing to run locally
|
|
79
|
+
if (!components.length) {
|
|
80
|
+
logger.log();
|
|
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
|
+
);
|
|
88
|
+
|
|
89
|
+
// The project does not contain any components that support local development
|
|
90
|
+
if (!runnableComponents.length) {
|
|
91
|
+
logger.log();
|
|
92
|
+
logger.error(i18n(`${i18nKey}.noRunnableComponents`));
|
|
93
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
94
|
+
}
|
|
95
95
|
|
|
96
|
-
logger.log(i18n(`${i18nKey}.header.betaMessage`));
|
|
97
96
|
logger.log();
|
|
97
|
+
const setupSucceeded = await this.devServerSetup(runnableComponents);
|
|
98
98
|
|
|
99
|
-
this.
|
|
99
|
+
if (setupSucceeded || !this.debug) {
|
|
100
|
+
console.clear();
|
|
101
|
+
}
|
|
102
|
+
|
|
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
144
|
|
|
121
|
-
|
|
145
|
+
const cleanupSucceeded = await this.devServerCleanup();
|
|
122
146
|
|
|
123
|
-
if (
|
|
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
|
-
if (exitCode === EXIT_CODES.SUCCESS) {
|
|
145
|
-
SpinniesManager.succeed('cleanupMessage', {
|
|
146
|
-
text: i18n(`${i18nKey}.exitingSucceed`),
|
|
147
|
-
});
|
|
148
|
-
} else {
|
|
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',
|
|
193
|
-
});
|
|
194
|
-
SpinniesManager.addOrUpdate('quitHelper', {
|
|
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',
|
|
154
|
+
SpinniesManager.succeed('cleanupMessage', {
|
|
155
|
+
text: i18n(`${i18nKey}.exitingSucceed`),
|
|
205
156
|
});
|
|
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
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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');
|
|
273
|
-
|
|
274
|
-
failedSubTasks.forEach(failedSubTask => {
|
|
275
|
-
SpinniesManager.add(null, {
|
|
276
|
-
text: failedSubTask.errorMessage,
|
|
277
|
-
status: 'fail',
|
|
278
|
-
failColor: 'white',
|
|
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);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
async createNewStagingBuild() {
|
|
303
|
-
try {
|
|
304
|
-
const { buildId } = await provisionBuild(
|
|
305
|
-
this.targetAccountId,
|
|
306
|
-
this.projectConfig.name,
|
|
307
|
-
this.projectConfig.platformVersion
|
|
168
|
+
logUploadWarning(reason) {
|
|
169
|
+
// Avoid logging the warning to the console if it is currently the most
|
|
170
|
+
// recently logged warning. We do not want to spam the console with the same message.
|
|
171
|
+
if (!this.uploadWarnings[reason]) {
|
|
172
|
+
const currentDefaultAccount = getConfigDefaultAccount();
|
|
173
|
+
const defaultAccountId = getAccountId(currentDefaultAccount);
|
|
174
|
+
|
|
175
|
+
logger.log();
|
|
176
|
+
logger.warn(i18n(`${i18nKey}.uploadWarning.header`, { reason }));
|
|
177
|
+
logger.log(
|
|
178
|
+
i18n(`${i18nKey}.uploadWarning.stopDev`, {
|
|
179
|
+
command: uiCommandReference('hs project dev'),
|
|
180
|
+
})
|
|
308
181
|
);
|
|
309
|
-
this.
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
182
|
+
if (this.targetAccountId !== defaultAccountId) {
|
|
183
|
+
logger.log(
|
|
184
|
+
i18n(`${i18nKey}.uploadWarning.runUploadWithAccount`, {
|
|
185
|
+
command: uiCommandReference(
|
|
186
|
+
`hs project upload --account=${this.targetAccountId}`
|
|
187
|
+
),
|
|
188
|
+
})
|
|
189
|
+
);
|
|
190
|
+
} else {
|
|
191
|
+
logger.log(
|
|
192
|
+
i18n(`${i18nKey}.uploadWarning.runUpload`, {
|
|
193
|
+
command: uiCommandReference('hs project upload'),
|
|
194
|
+
})
|
|
195
|
+
);
|
|
318
196
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
197
|
+
logger.log(
|
|
198
|
+
i18n(`${i18nKey}.uploadWarning.restartDev`, {
|
|
199
|
+
command: uiCommandReference('hs project dev'),
|
|
200
|
+
})
|
|
201
|
+
);
|
|
322
202
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
await this.createNewStagingBuild();
|
|
203
|
+
this.mostRecentUploadWarning = reason;
|
|
204
|
+
this.uploadWarnings[reason] = true;
|
|
326
205
|
}
|
|
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
206
|
}
|
|
341
207
|
|
|
342
|
-
|
|
343
|
-
const
|
|
344
|
-
event,
|
|
345
|
-
filePath,
|
|
346
|
-
remotePath: path.relative(this.projectSourceDir, filePath),
|
|
347
|
-
};
|
|
208
|
+
monitorConsoleOutput() {
|
|
209
|
+
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
348
210
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
this.addChangeToStandbyQueue({ ...changeInfo, supported: false });
|
|
211
|
+
process.stdout.write = function(chunk, encoding, callback) {
|
|
212
|
+
// Reset the most recently logged warning
|
|
213
|
+
if (
|
|
214
|
+
this.mostRecentUploadWarning &&
|
|
215
|
+
this.uploadWarnings[this.mostRecentUploadWarning]
|
|
216
|
+
) {
|
|
217
|
+
delete this.uploadWarnings[this.mostRecentUploadWarning];
|
|
218
|
+
}
|
|
359
219
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
}
|
|
220
|
+
return originalStdoutWrite(chunk, encoding, callback);
|
|
221
|
+
}.bind(this);
|
|
363
222
|
}
|
|
364
223
|
|
|
365
|
-
|
|
366
|
-
const
|
|
224
|
+
compareLocalProjectToDeployed(runnableComponents) {
|
|
225
|
+
const deployedComponentNames = this.deployedBuild.subbuildStatuses.map(
|
|
226
|
+
subbuildStatus => subbuildStatus.buildName
|
|
227
|
+
);
|
|
367
228
|
|
|
368
|
-
|
|
369
|
-
this.updateDevModeStatus('noUploadsAllowed');
|
|
229
|
+
let missingComponents = [];
|
|
370
230
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
}),
|
|
375
|
-
status: 'fail',
|
|
376
|
-
failColor: 'white',
|
|
377
|
-
noIndent: true,
|
|
378
|
-
});
|
|
379
|
-
} else {
|
|
380
|
-
this.updateDevModeStatus('manualUploadRequired');
|
|
231
|
+
runnableComponents.forEach(({ type, config, path }) => {
|
|
232
|
+
if (type === COMPONENT_TYPES.app) {
|
|
233
|
+
const cardConfigs = getAppCardConfigs(config, path);
|
|
381
234
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
235
|
+
if (!deployedComponentNames.includes(config.name)) {
|
|
236
|
+
missingComponents.push(
|
|
237
|
+
`${i18n(`${i18nKey}.uploadWarning.appLabel`)} ${config.name}`
|
|
238
|
+
);
|
|
239
|
+
}
|
|
386
240
|
|
|
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,
|
|
241
|
+
cardConfigs.forEach(cardConfig => {
|
|
242
|
+
if (
|
|
243
|
+
cardConfig.data &&
|
|
244
|
+
cardConfig.data.title &&
|
|
245
|
+
!deployedComponentNames.includes(cardConfig.data.title)
|
|
246
|
+
) {
|
|
247
|
+
missingComponents.push(
|
|
248
|
+
`${i18n(`${i18nKey}.uploadWarning.appLabel`)} ${
|
|
249
|
+
cardConfig.data.title
|
|
250
|
+
}`
|
|
251
|
+
);
|
|
252
|
+
}
|
|
408
253
|
});
|
|
409
254
|
}
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
if (missingComponents.length) {
|
|
258
|
+
this.logUploadWarning(
|
|
259
|
+
i18n(`${i18nKey}.uploadWarning.missingComponents`, {
|
|
260
|
+
missingComponents: missingComponents.join(', '),
|
|
261
|
+
})
|
|
262
|
+
);
|
|
410
263
|
}
|
|
411
264
|
}
|
|
412
265
|
|
|
413
|
-
|
|
414
|
-
|
|
266
|
+
startWatching(runnableComponents) {
|
|
267
|
+
this.watcher = chokidar.watch(this.projectDir, {
|
|
268
|
+
ignoreInitial: true,
|
|
269
|
+
});
|
|
415
270
|
|
|
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',
|
|
271
|
+
const configPaths = runnableComponents
|
|
272
|
+
.filter(({ type }) => type === COMPONENT_TYPES.app)
|
|
273
|
+
.map(component => {
|
|
274
|
+
const appConfigPath = path.join(component.path, APP_COMPONENT_CONFIG);
|
|
275
|
+
return appConfigPath;
|
|
433
276
|
});
|
|
434
|
-
return false;
|
|
435
|
-
}
|
|
436
277
|
|
|
437
|
-
const
|
|
438
|
-
|
|
439
|
-
);
|
|
278
|
+
const projectConfigPath = path.join(this.projectDir, PROJECT_CONFIG_FILE);
|
|
279
|
+
configPaths.push(projectConfigPath);
|
|
440
280
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
this.
|
|
446
|
-
}
|
|
447
|
-
|
|
281
|
+
this.watcher.on('add', filePath => {
|
|
282
|
+
this.handleWatchEvent(filePath, WATCH_EVENTS.add, configPaths);
|
|
283
|
+
});
|
|
284
|
+
this.watcher.on('change', filePath => {
|
|
285
|
+
this.handleWatchEvent(filePath, WATCH_EVENTS.change, configPaths);
|
|
286
|
+
});
|
|
287
|
+
this.watcher.on('unlink', filePath => {
|
|
288
|
+
this.handleWatchEvent(filePath, WATCH_EVENTS.unlink, configPaths);
|
|
289
|
+
});
|
|
290
|
+
this.watcher.on('unlinkDir', filePath => {
|
|
291
|
+
this.handleWatchEvent(filePath, WATCH_EVENTS.unlinkDir, configPaths);
|
|
292
|
+
});
|
|
448
293
|
}
|
|
449
294
|
|
|
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
|
-
}
|
|
295
|
+
async stopWatching() {
|
|
296
|
+
await this.watcher.close();
|
|
500
297
|
}
|
|
501
298
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
299
|
+
handleWatchEvent(filePath, event, configPaths) {
|
|
300
|
+
if (configPaths.includes(filePath)) {
|
|
301
|
+
this.logUploadWarning(
|
|
302
|
+
i18n(`${i18nKey}.uploadWarning.configEdit`, {
|
|
303
|
+
path: path.relative(this.projectDir, filePath),
|
|
304
|
+
})
|
|
305
|
+
);
|
|
306
|
+
} else {
|
|
307
|
+
this.devServerFileChange(filePath, event);
|
|
511
308
|
}
|
|
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
309
|
}
|
|
523
310
|
|
|
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
|
-
|
|
311
|
+
async devServerSetup(components) {
|
|
539
312
|
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,
|
|
313
|
+
await DevServerManager.setup({
|
|
314
|
+
components,
|
|
315
|
+
debug: this.debug,
|
|
316
|
+
onUploadRequired: this.logUploadWarning.bind(this),
|
|
561
317
|
});
|
|
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
|
-
});
|
|
318
|
+
return true;
|
|
319
|
+
} catch (e) {
|
|
320
|
+
if (this.debug) {
|
|
321
|
+
logger.error(e);
|
|
584
322
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
this.targetAccountId,
|
|
588
|
-
this.projectConfig,
|
|
589
|
-
null,
|
|
590
|
-
this.currentStagedBuildId,
|
|
591
|
-
true
|
|
323
|
+
logger.error(
|
|
324
|
+
i18n(`${i18nKey}.devServer.setupError`, { message: e.message })
|
|
592
325
|
);
|
|
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
|
-
}
|
|
620
|
-
}
|
|
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
|
-
})
|
|
653
|
-
);
|
|
654
|
-
this.standbyChanges = [];
|
|
326
|
+
return false;
|
|
655
327
|
}
|
|
656
328
|
}
|
|
657
329
|
|
|
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
330
|
async devServerStart() {
|
|
670
331
|
try {
|
|
671
|
-
// Set this to true manually for now
|
|
672
|
-
DevServerManager.initialized = true;
|
|
673
|
-
|
|
674
332
|
await DevServerManager.start({
|
|
675
333
|
accountId: this.targetAccountId,
|
|
676
|
-
debug: this.debug,
|
|
677
|
-
spinniesLogger: this.handleServerLog,
|
|
678
334
|
projectConfig: this.projectConfig,
|
|
679
|
-
projectSourceDir: this.projectSourceDir,
|
|
680
335
|
});
|
|
681
336
|
} catch (e) {
|
|
682
337
|
if (this.debug) {
|
|
683
338
|
logger.error(e);
|
|
684
339
|
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
340
|
+
logger.error(
|
|
341
|
+
i18n(`${i18nKey}.devServer.startError`, { message: e.message })
|
|
342
|
+
);
|
|
343
|
+
process.exit(EXIT_CODES.ERROR);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
devServerFileChange(filePath, event) {
|
|
348
|
+
try {
|
|
349
|
+
DevServerManager.fileChange({ filePath, event });
|
|
350
|
+
} catch (e) {
|
|
351
|
+
if (this.debug) {
|
|
352
|
+
logger.error(e);
|
|
353
|
+
}
|
|
354
|
+
logger.error(
|
|
355
|
+
i18n(`${i18nKey}.devServer.fileChangeError`, {
|
|
356
|
+
message: e.message,
|
|
357
|
+
})
|
|
358
|
+
);
|
|
689
359
|
}
|
|
690
360
|
}
|
|
691
361
|
|
|
692
362
|
async devServerCleanup() {
|
|
693
363
|
try {
|
|
694
364
|
await DevServerManager.cleanup();
|
|
365
|
+
return true;
|
|
695
366
|
} catch (e) {
|
|
696
367
|
if (this.debug) {
|
|
697
368
|
logger.error(e);
|
|
698
369
|
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
370
|
+
logger.error(
|
|
371
|
+
i18n(`${i18nKey}.devServer.cleanupError`, { message: e.message })
|
|
372
|
+
);
|
|
373
|
+
return false;
|
|
703
374
|
}
|
|
704
375
|
}
|
|
705
376
|
}
|
|
706
377
|
|
|
707
|
-
module.exports =
|
|
378
|
+
module.exports = LocalDevManager;
|