@hubspot/cli 3.0.10-beta.0 → 3.0.10-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commands/project/upload.js +63 -7
- package/lib/links.js +10 -0
- package/lib/projects.js +111 -170
- package/package.json +5 -4
|
@@ -32,6 +32,7 @@ const {
|
|
|
32
32
|
validateProjectConfig,
|
|
33
33
|
pollBuildStatus,
|
|
34
34
|
ensureProjectExists,
|
|
35
|
+
pollDeployStatus,
|
|
35
36
|
} = require('../../lib/projects');
|
|
36
37
|
|
|
37
38
|
const loadAndValidateOptions = async options => {
|
|
@@ -50,7 +51,9 @@ exports.command = 'upload [path]';
|
|
|
50
51
|
exports.describe = false;
|
|
51
52
|
|
|
52
53
|
const uploadProjectFiles = async (accountId, projectName, filePath) => {
|
|
53
|
-
const spinnies = new Spinnies(
|
|
54
|
+
const spinnies = new Spinnies({
|
|
55
|
+
succeedColor: 'white',
|
|
56
|
+
});
|
|
54
57
|
|
|
55
58
|
spinnies.add('upload', {
|
|
56
59
|
text: `Uploading ${chalk.bold(projectName)} project files to ${chalk.bold(
|
|
@@ -96,11 +99,7 @@ const uploadProjectFiles = async (accountId, projectName, filePath) => {
|
|
|
96
99
|
);
|
|
97
100
|
}
|
|
98
101
|
|
|
99
|
-
|
|
100
|
-
await pollBuildStatus(accountId, projectName, buildId);
|
|
101
|
-
} catch (err) {
|
|
102
|
-
logger.log(err);
|
|
103
|
-
}
|
|
102
|
+
return { buildId };
|
|
104
103
|
};
|
|
105
104
|
|
|
106
105
|
exports.handler = async options => {
|
|
@@ -130,7 +129,64 @@ exports.handler = async options => {
|
|
|
130
129
|
output.on('close', async function() {
|
|
131
130
|
logger.debug(`Project files compressed: ${archive.pointer()} bytes`);
|
|
132
131
|
|
|
133
|
-
await uploadProjectFiles(
|
|
132
|
+
const { buildId } = await uploadProjectFiles(
|
|
133
|
+
accountId,
|
|
134
|
+
projectConfig.name,
|
|
135
|
+
tempFile.name
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
const {
|
|
139
|
+
isAutoDeployEnabled,
|
|
140
|
+
deployStatusTaskLocator,
|
|
141
|
+
status,
|
|
142
|
+
subbuildStatuses,
|
|
143
|
+
} = await pollBuildStatus(accountId, projectConfig.name, buildId);
|
|
144
|
+
|
|
145
|
+
if (status === 'FAILURE') {
|
|
146
|
+
const failedSubbuilds = subbuildStatuses.filter(
|
|
147
|
+
subbuild => subbuild.status === 'FAILURE'
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
logger.log('-'.repeat(50));
|
|
151
|
+
logger.log(
|
|
152
|
+
`Build #${buildId} failed because there was a problem\nbuilding ${
|
|
153
|
+
failedSubbuilds.length === 1
|
|
154
|
+
? failedSubbuilds[0].buildName
|
|
155
|
+
: failedSubbuilds.length + ' components'
|
|
156
|
+
}\n`
|
|
157
|
+
);
|
|
158
|
+
logger.log('See below for a summary of errors.');
|
|
159
|
+
logger.log('-'.repeat(50));
|
|
160
|
+
|
|
161
|
+
failedSubbuilds.forEach(subbuild => {
|
|
162
|
+
logger.log(
|
|
163
|
+
`\n--- ${subbuild.buildName} failed to build with the following error ---`
|
|
164
|
+
);
|
|
165
|
+
logger.error(subbuild.errorMessage);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (isAutoDeployEnabled && deployStatusTaskLocator) {
|
|
172
|
+
logger.log(
|
|
173
|
+
`Build #${buildId} succeeded. ${chalk.bold(
|
|
174
|
+
'Automatically deploying'
|
|
175
|
+
)} to ${accountId}`
|
|
176
|
+
);
|
|
177
|
+
await pollDeployStatus(
|
|
178
|
+
accountId,
|
|
179
|
+
projectConfig.name,
|
|
180
|
+
deployStatusTaskLocator.id,
|
|
181
|
+
buildId
|
|
182
|
+
);
|
|
183
|
+
} else {
|
|
184
|
+
logger.log('-'.repeat(50));
|
|
185
|
+
logger.log(chalk.bold(`Build #${buildId} succeeded\n`));
|
|
186
|
+
logger.log('🚀 Ready to take your project live?');
|
|
187
|
+
logger.log(`Run \`${chalk.hex('f5c26b')('hs project deploy')}\``);
|
|
188
|
+
logger.log('-'.repeat(50));
|
|
189
|
+
}
|
|
134
190
|
|
|
135
191
|
try {
|
|
136
192
|
tempFile.removeCallback();
|
package/lib/links.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const supportsHyperlinks = require('supports-hyperlinks');
|
|
1
2
|
const { getEnv } = require('@hubspot/cli-lib/lib/config');
|
|
2
3
|
const { ENVIRONMENTS } = require('@hubspot/cli-lib/lib/constants');
|
|
3
4
|
const { getHubSpotWebsiteOrigin } = require('@hubspot/cli-lib/lib/urls');
|
|
@@ -120,9 +121,18 @@ const openLink = (accountId, shortcut) => {
|
|
|
120
121
|
logger.success(`We opened ${match.url} in your browser`);
|
|
121
122
|
};
|
|
122
123
|
|
|
124
|
+
const link = (linkText, url) => {
|
|
125
|
+
if (supportsHyperlinks.stdout) {
|
|
126
|
+
return ['\u001B]8;;', url, '\u0007', linkText, '\u001B]8;;\u0007'].join('');
|
|
127
|
+
} else {
|
|
128
|
+
return `${linkText}: ${url}`;
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
123
132
|
module.exports = {
|
|
124
133
|
getSiteLinks,
|
|
125
134
|
getSiteLinksAsArray,
|
|
126
135
|
logSiteLinks,
|
|
127
136
|
openLink,
|
|
137
|
+
link,
|
|
128
138
|
};
|
package/lib/projects.js
CHANGED
|
@@ -11,10 +11,8 @@ const { getHubSpotWebsiteOrigin } = require('@hubspot/cli-lib/lib/urls');
|
|
|
11
11
|
const {
|
|
12
12
|
ENVIRONMENTS,
|
|
13
13
|
POLLING_DELAY,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
PROJECT_DEPLOY_STATUS,
|
|
17
|
-
PROJECT_DEPLOY_STATUS_TEXT,
|
|
14
|
+
PROJECT_OVERALL_STATUS,
|
|
15
|
+
PROJECT_TEXT,
|
|
18
16
|
} = require('@hubspot/cli-lib/lib/constants');
|
|
19
17
|
const {
|
|
20
18
|
getBuildStatus,
|
|
@@ -27,10 +25,29 @@ const {
|
|
|
27
25
|
ApiErrorContext,
|
|
28
26
|
} = require('@hubspot/cli-lib/errorHandlers');
|
|
29
27
|
|
|
30
|
-
const
|
|
28
|
+
const PROJECT_STRINGS = {
|
|
29
|
+
BUILD: {
|
|
30
|
+
INITIALIZE: (name, numOfComponents) =>
|
|
31
|
+
`Building ${chalk.bold(
|
|
32
|
+
name
|
|
33
|
+
)}\n\nFound ${numOfComponents} components in this project ...\n`,
|
|
34
|
+
SUCCESS: name => `Built ${chalk.bold(name)}`,
|
|
35
|
+
FAIL: name => `Failed to build ${chalk.bold(name)}`,
|
|
36
|
+
},
|
|
37
|
+
DEPLOY: {
|
|
38
|
+
INITIALIZE: (name, numOfComponents) =>
|
|
39
|
+
`Deploying ${chalk.bold(
|
|
40
|
+
name
|
|
41
|
+
)}\n\nFound ${numOfComponents} components in this project ...\n`,
|
|
42
|
+
SUCCESS: name => `Deployed ${chalk.bold(name)}`,
|
|
43
|
+
FAIL: name => `Failed to deploy ${chalk.bold(name)}`,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const isTaskComplete = task => {
|
|
31
48
|
return (
|
|
32
|
-
|
|
33
|
-
|
|
49
|
+
task.status === PROJECT_OVERALL_STATUS.SUCCESS ||
|
|
50
|
+
task.status === PROJECT_OVERALL_STATUS.FAILURE
|
|
34
51
|
);
|
|
35
52
|
};
|
|
36
53
|
|
|
@@ -188,183 +205,107 @@ const showWelcomeMessage = (projectName, accountId) => {
|
|
|
188
205
|
);
|
|
189
206
|
};
|
|
190
207
|
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
208
|
+
const makeGetTaskStatus = taskType => {
|
|
209
|
+
let statusFn, statusText, statusStrings;
|
|
210
|
+
switch (taskType) {
|
|
211
|
+
case 'build':
|
|
212
|
+
statusFn = getBuildStatus;
|
|
213
|
+
statusText = PROJECT_TEXT.BUILD;
|
|
214
|
+
statusStrings = PROJECT_STRINGS.BUILD;
|
|
215
|
+
break;
|
|
216
|
+
case 'deploy':
|
|
217
|
+
statusFn = getDeployStatus;
|
|
218
|
+
statusText = PROJECT_TEXT.DEPLOY;
|
|
219
|
+
statusStrings = PROJECT_STRINGS.DEPLOY;
|
|
220
|
+
break;
|
|
221
|
+
default:
|
|
222
|
+
logger.error(`Cannot get status for task type ${taskType}`);
|
|
223
|
+
}
|
|
200
224
|
|
|
201
|
-
|
|
202
|
-
spinnies
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}`,
|
|
225
|
+
return async (accountId, taskName, taskId) => {
|
|
226
|
+
const spinnies = new Spinnies({
|
|
227
|
+
succeedColor: 'white',
|
|
228
|
+
failColor: 'white',
|
|
206
229
|
});
|
|
207
|
-
}
|
|
208
230
|
|
|
209
|
-
|
|
210
|
-
const pollInterval = setInterval(async () => {
|
|
211
|
-
const buildStatus = await getBuildStatus(accountId, name, buildId).catch(
|
|
212
|
-
reject
|
|
213
|
-
);
|
|
214
|
-
const { status, subbuildStatuses } = buildStatus;
|
|
215
|
-
|
|
216
|
-
if (spinnies.hasActiveSpinners()) {
|
|
217
|
-
subbuildStatuses.forEach(subBuild => {
|
|
218
|
-
if (!spinnies.pick(subBuild.buildName)) {
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
231
|
+
spinnies.add('overallTaskStatus', { text: 'Beginning' });
|
|
221
232
|
|
|
222
|
-
|
|
223
|
-
PROJECT_BUILD_STATUS_TEXT[subBuild.status]
|
|
224
|
-
}`;
|
|
233
|
+
const initialTaskStatus = await statusFn(accountId, taskName, taskId);
|
|
225
234
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
case PROJECT_BUILD_STATUS.FAILURE:
|
|
233
|
-
spinnies.fail(subBuild.buildName, {
|
|
234
|
-
text: updatedText,
|
|
235
|
-
});
|
|
236
|
-
break;
|
|
237
|
-
default:
|
|
238
|
-
spinnies.update(subBuild.buildName, {
|
|
239
|
-
text: updatedText,
|
|
240
|
-
});
|
|
241
|
-
break;
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
if (isBuildComplete(buildStatus)) {
|
|
247
|
-
clearInterval(pollInterval);
|
|
248
|
-
|
|
249
|
-
if (status === PROJECT_BUILD_STATUS.SUCCESS) {
|
|
250
|
-
logger.success(
|
|
251
|
-
`Your project ${chalk.bold(name)} ${
|
|
252
|
-
PROJECT_BUILD_STATUS_TEXT[status]
|
|
253
|
-
}.`
|
|
254
|
-
);
|
|
255
|
-
} else if (status === PROJECT_BUILD_STATUS.FAILURE) {
|
|
256
|
-
logger.error(
|
|
257
|
-
`Your project ${chalk.bold(name)} ${
|
|
258
|
-
PROJECT_BUILD_STATUS_TEXT[status]
|
|
259
|
-
}.`
|
|
260
|
-
);
|
|
261
|
-
subbuildStatuses.forEach(subBuild => {
|
|
262
|
-
if (subBuild.status === PROJECT_BUILD_STATUS.FAILURE) {
|
|
263
|
-
logger.error(
|
|
264
|
-
`${chalk.bold(subBuild.buildName)} failed to build. ${
|
|
265
|
-
subBuild.errorMessage
|
|
266
|
-
}.`
|
|
267
|
-
);
|
|
268
|
-
}
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
resolve(buildStatus);
|
|
272
|
-
}
|
|
273
|
-
}, POLLING_DELAY);
|
|
274
|
-
});
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
const pollDeployStatus = async (accountId, name, deployId, deployedBuildId) => {
|
|
278
|
-
const deployStatus = await getDeployStatus(accountId, name, deployId);
|
|
279
|
-
const spinnies = new Spinnies();
|
|
235
|
+
spinnies.update('overallTaskStatus', {
|
|
236
|
+
text: statusStrings.INITIALIZE(
|
|
237
|
+
taskName,
|
|
238
|
+
initialTaskStatus[statusText.SUBTASK_KEY].length
|
|
239
|
+
),
|
|
240
|
+
});
|
|
280
241
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
242
|
+
for (let subTask of initialTaskStatus[statusText.SUBTASK_KEY]) {
|
|
243
|
+
spinnies.add(subTask[statusText.SUBTASK_NAME_KEY], {
|
|
244
|
+
text: `${chalk.bold(subTask[statusText.SUBTASK_NAME_KEY])} #${taskId} ${
|
|
245
|
+
statusText.STATUS_TEXT[statusText.STATES.ENQUEUED]
|
|
246
|
+
}\n`,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
288
249
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
});
|
|
295
|
-
}
|
|
250
|
+
return new Promise((resolve, reject) => {
|
|
251
|
+
const pollInterval = setInterval(async () => {
|
|
252
|
+
const taskStatus = await statusFn(accountId, taskName, taskId).catch(
|
|
253
|
+
reject
|
|
254
|
+
);
|
|
296
255
|
|
|
297
|
-
|
|
298
|
-
const pollInterval = setInterval(async () => {
|
|
299
|
-
const deployStatus = await getDeployStatus(
|
|
300
|
-
accountId,
|
|
301
|
-
name,
|
|
302
|
-
deployId
|
|
303
|
-
).catch(reject);
|
|
256
|
+
const { status, [statusText.SUBTASK_KEY]: subTaskStatus } = taskStatus;
|
|
304
257
|
|
|
305
|
-
|
|
258
|
+
if (spinnies.hasActiveSpinners()) {
|
|
259
|
+
subTaskStatus.forEach(subTask => {
|
|
260
|
+
if (!spinnies.pick(subTask[statusText.SUBTASK_NAME_KEY])) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
306
263
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
264
|
+
const updatedText = `${chalk.bold(
|
|
265
|
+
subTask[statusText.SUBTASK_NAME_KEY]
|
|
266
|
+
)} #${taskId} ${statusText.STATUS_TEXT[subTask.status]}\n`;
|
|
267
|
+
|
|
268
|
+
switch (subTask.status) {
|
|
269
|
+
case statusText.STATES.SUCCESS:
|
|
270
|
+
spinnies.succeed(subTask[statusText.SUBTASK_NAME_KEY], {
|
|
271
|
+
text: updatedText,
|
|
272
|
+
});
|
|
273
|
+
break;
|
|
274
|
+
case statusText.STATES.FAILURE:
|
|
275
|
+
spinnies.fail(subTask.buildName, {
|
|
276
|
+
text: updatedText,
|
|
277
|
+
});
|
|
278
|
+
break;
|
|
279
|
+
default:
|
|
280
|
+
spinnies.update(subTask.buildName, {
|
|
281
|
+
text: updatedText,
|
|
282
|
+
});
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
});
|
|
312
286
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
}`;
|
|
287
|
+
if (isTaskComplete(taskStatus)) {
|
|
288
|
+
subTaskStatus.forEach(subBuild => {
|
|
289
|
+
spinnies.remove(subBuild[statusText.SUBTASK_NAME_KEY]);
|
|
290
|
+
});
|
|
318
291
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
text: updatedText,
|
|
323
|
-
});
|
|
324
|
-
break;
|
|
325
|
-
case PROJECT_DEPLOY_STATUS.FAILURE:
|
|
326
|
-
spinnies.fail(subdeploy.deployName, {
|
|
327
|
-
text: updatedText,
|
|
292
|
+
if (status === statusText.STATES.SUCCESS) {
|
|
293
|
+
spinnies.succeed('overallTaskStatus', {
|
|
294
|
+
text: statusStrings.SUCCESS(taskName),
|
|
328
295
|
});
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
text: updatedText,
|
|
296
|
+
} else if (status === statusText.STATES.FAILURE) {
|
|
297
|
+
spinnies.fail('overallTaskStatus', {
|
|
298
|
+
text: statusStrings.FAIL(taskName),
|
|
333
299
|
});
|
|
334
|
-
break;
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
if (isBuildComplete(deployStatus)) {
|
|
340
|
-
clearInterval(pollInterval);
|
|
341
|
-
|
|
342
|
-
if (status === PROJECT_DEPLOY_STATUS.SUCCESS) {
|
|
343
|
-
logger.success(
|
|
344
|
-
`Your project ${chalk.bold(name)} ${
|
|
345
|
-
PROJECT_DEPLOY_STATUS_TEXT[status]
|
|
346
|
-
}.`
|
|
347
|
-
);
|
|
348
|
-
} else if (status === PROJECT_DEPLOY_STATUS.FAILURE) {
|
|
349
|
-
logger.error(
|
|
350
|
-
`Your project ${chalk.bold(name)} ${
|
|
351
|
-
PROJECT_DEPLOY_STATUS_TEXT[status]
|
|
352
|
-
}.`
|
|
353
|
-
);
|
|
354
|
-
subdeployStatuses.forEach(subdeploy => {
|
|
355
|
-
if (subdeploy.status === PROJECT_DEPLOY_STATUS.FAILURE) {
|
|
356
|
-
logger.error(
|
|
357
|
-
`${chalk.bold(subdeploy.deployName)} failed to build. ${
|
|
358
|
-
subdeploy.errorMessage
|
|
359
|
-
}.`
|
|
360
|
-
);
|
|
361
300
|
}
|
|
362
|
-
|
|
301
|
+
|
|
302
|
+
clearInterval(pollInterval);
|
|
303
|
+
resolve(taskStatus);
|
|
304
|
+
}
|
|
363
305
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
});
|
|
306
|
+
}, POLLING_DELAY);
|
|
307
|
+
});
|
|
308
|
+
};
|
|
368
309
|
};
|
|
369
310
|
|
|
370
311
|
module.exports = {
|
|
@@ -373,7 +314,7 @@ module.exports = {
|
|
|
373
314
|
getOrCreateProjectConfig,
|
|
374
315
|
validateProjectConfig,
|
|
375
316
|
showWelcomeMessage,
|
|
376
|
-
pollBuildStatus,
|
|
377
|
-
pollDeployStatus,
|
|
317
|
+
pollBuildStatus: makeGetTaskStatus('build'),
|
|
318
|
+
pollDeployStatus: makeGetTaskStatus('deploy'),
|
|
378
319
|
ensureProjectExists,
|
|
379
320
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "3.0.10-beta.
|
|
3
|
+
"version": "3.0.10-beta.1",
|
|
4
4
|
"description": "CLI for working with HubSpot",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"url": "https://github.com/HubSpot/hubspot-cms-tools"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@hubspot/cli-lib": "^3.0.10-beta.
|
|
12
|
-
"@hubspot/serverless-dev-runtime": "^3.0.10-beta.
|
|
11
|
+
"@hubspot/cli-lib": "^3.0.10-beta.1",
|
|
12
|
+
"@hubspot/serverless-dev-runtime": "^3.0.10-beta.1",
|
|
13
13
|
"archiver": "^5.3.0",
|
|
14
14
|
"chalk": "^4.1.0",
|
|
15
15
|
"express": "^4.17.1",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"ora": "^4.0.3",
|
|
21
21
|
"shelljs": "0.8.3",
|
|
22
22
|
"spinnies": "^0.5.1",
|
|
23
|
+
"supports-hyperlinks": "^2.2.0",
|
|
23
24
|
"tmp": "^0.2.1",
|
|
24
25
|
"update-notifier": "3.0.1",
|
|
25
26
|
"yargs": "15.4.1"
|
|
@@ -37,5 +38,5 @@
|
|
|
37
38
|
"publishConfig": {
|
|
38
39
|
"access": "public"
|
|
39
40
|
},
|
|
40
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "d3426a88d8355cdae053f02853a535c09ba84a7b"
|
|
41
42
|
}
|