@hubspot/cli 4.2.1-beta.1 → 4.2.1-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +1 -1
- package/commands/accounts/list.js +1 -1
- package/commands/project/add.js +1 -1
- package/commands/project/dev.js +50 -27
- package/commands/project/listBuilds.js +4 -1
- package/commands/project/upload.js +3 -0
- package/commands/project/watch.js +3 -0
- package/commands/project.js +9 -6
- package/commands/sandbox/create.js +10 -1
- package/commands/sandbox/delete.js +7 -11
- package/lang/en.lyaml +31 -12
- package/lib/DevServerManager.js +109 -58
- package/lib/LocalDevManager.js +10 -2
- package/lib/LocalDevManagerV2.js +118 -8
- package/lib/projectStructure.js +106 -0
- package/lib/projects.js +32 -3
- package/lib/ui.js +6 -1
- package/lib/usageTracking.js +57 -0
- package/package.json +5 -5
package/bin/cli.js
CHANGED
package/commands/project/add.js
CHANGED
|
@@ -11,7 +11,7 @@ const { loadAndValidateOptions } = require('../../lib/validation');
|
|
|
11
11
|
const i18nKey = 'cli.commands.project.subcommands.add';
|
|
12
12
|
|
|
13
13
|
exports.command = 'add';
|
|
14
|
-
exports.describe =
|
|
14
|
+
exports.describe = i18n(`${i18nKey}.describe`);
|
|
15
15
|
|
|
16
16
|
exports.handler = async options => {
|
|
17
17
|
await loadAndValidateOptions(options);
|
package/commands/project/dev.js
CHANGED
|
@@ -5,7 +5,10 @@ const {
|
|
|
5
5
|
addUseEnvironmentOptions,
|
|
6
6
|
addTestingOptions,
|
|
7
7
|
} = require('../../lib/commonOpts');
|
|
8
|
-
const {
|
|
8
|
+
const {
|
|
9
|
+
trackCommandUsage,
|
|
10
|
+
trackCommandMetadataUsage,
|
|
11
|
+
} = require('../../lib/usageTracking');
|
|
9
12
|
const { loadAndValidateOptions } = require('../../lib/validation');
|
|
10
13
|
const { i18n } = require('../../lib/lang');
|
|
11
14
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
@@ -17,6 +20,7 @@ const {
|
|
|
17
20
|
ensureProjectExists,
|
|
18
21
|
handleProjectUpload,
|
|
19
22
|
pollProjectBuildAndDeploy,
|
|
23
|
+
showPlatformVersionWarning,
|
|
20
24
|
} = require('../../lib/projects');
|
|
21
25
|
const { EXIT_CODES } = require('../../lib/enums/exitCodes');
|
|
22
26
|
const { uiAccountDescription, uiBetaMessage, uiLine } = require('../../lib/ui');
|
|
@@ -60,7 +64,7 @@ const {
|
|
|
60
64
|
const i18nKey = 'cli.commands.project.subcommands.dev';
|
|
61
65
|
|
|
62
66
|
exports.command = 'dev [--account]';
|
|
63
|
-
exports.describe =
|
|
67
|
+
exports.describe = i18n(`${i18nKey}.describe`);
|
|
64
68
|
|
|
65
69
|
exports.handler = async options => {
|
|
66
70
|
await loadAndValidateOptions(options);
|
|
@@ -79,6 +83,8 @@ exports.handler = async options => {
|
|
|
79
83
|
process.exit(EXIT_CODES.ERROR);
|
|
80
84
|
}
|
|
81
85
|
|
|
86
|
+
await showPlatformVersionWarning(accountId, projectConfig);
|
|
87
|
+
|
|
82
88
|
const accounts = getConfigAccounts();
|
|
83
89
|
let targetAccountId = options.account ? accountId : null;
|
|
84
90
|
let createNewSandbox = false;
|
|
@@ -129,6 +135,13 @@ exports.handler = async options => {
|
|
|
129
135
|
}
|
|
130
136
|
try {
|
|
131
137
|
const { name } = await sandboxNamePrompt(DEVELOPER_SANDBOX);
|
|
138
|
+
|
|
139
|
+
trackCommandMetadataUsage(
|
|
140
|
+
'sandbox-create',
|
|
141
|
+
{ step: 'project-dev' },
|
|
142
|
+
accountId
|
|
143
|
+
);
|
|
144
|
+
|
|
132
145
|
const { result } = await buildSandbox({
|
|
133
146
|
name,
|
|
134
147
|
type: DEVELOPER_SANDBOX,
|
|
@@ -176,12 +189,13 @@ exports.handler = async options => {
|
|
|
176
189
|
? UPLOAD_PERMISSIONS.manual
|
|
177
190
|
: UPLOAD_PERMISSIONS.always;
|
|
178
191
|
|
|
192
|
+
let deployedBuild;
|
|
193
|
+
|
|
179
194
|
if (projectExists) {
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
)
|
|
184
|
-
if (options.extension || sourceIntegration) {
|
|
195
|
+
const project = await fetchProject(targetAccountId, projectConfig.name);
|
|
196
|
+
deployedBuild = project.deployedBuild;
|
|
197
|
+
|
|
198
|
+
if (options.local || options.localAll || project.sourceIntegration) {
|
|
185
199
|
uploadPermission = UPLOAD_PERMISSIONS.never;
|
|
186
200
|
}
|
|
187
201
|
}
|
|
@@ -285,7 +299,7 @@ exports.handler = async options => {
|
|
|
285
299
|
// Do this before starting the dev server for v2 behavior because we cannot
|
|
286
300
|
// run a server on a broken project
|
|
287
301
|
if (
|
|
288
|
-
options.
|
|
302
|
+
(options.local || options.localAll) &&
|
|
289
303
|
initialUploadResult &&
|
|
290
304
|
!initialUploadResult.succeeded
|
|
291
305
|
) {
|
|
@@ -314,27 +328,30 @@ exports.handler = async options => {
|
|
|
314
328
|
|
|
315
329
|
SpinniesManager.remove('devModeSetup');
|
|
316
330
|
|
|
317
|
-
const LocalDev =
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
331
|
+
const LocalDev =
|
|
332
|
+
options.local || options.localAll
|
|
333
|
+
? new LocalDevManagerV2({
|
|
334
|
+
alpha: options.localAll,
|
|
335
|
+
debug: options.debug,
|
|
336
|
+
deployedBuild,
|
|
337
|
+
projectConfig,
|
|
338
|
+
projectDir,
|
|
339
|
+
targetAccountId,
|
|
340
|
+
})
|
|
341
|
+
: new LocalDevManager({
|
|
342
|
+
debug: options.debug,
|
|
343
|
+
projectConfig,
|
|
344
|
+
projectDir,
|
|
345
|
+
targetAccountId,
|
|
346
|
+
uploadPermission,
|
|
347
|
+
});
|
|
332
348
|
|
|
333
349
|
await LocalDev.start();
|
|
334
350
|
|
|
335
351
|
// Let the user know when the initial build or deploy fails
|
|
336
352
|
if (
|
|
337
|
-
!options.
|
|
353
|
+
!options.local &&
|
|
354
|
+
!options.localAll &&
|
|
338
355
|
initialUploadResult &&
|
|
339
356
|
!initialUploadResult.succeeded
|
|
340
357
|
) {
|
|
@@ -354,9 +371,15 @@ exports.builder = yargs => {
|
|
|
354
371
|
addUseEnvironmentOptions(yargs, true);
|
|
355
372
|
addTestingOptions(yargs, true);
|
|
356
373
|
|
|
357
|
-
yargs.option('
|
|
358
|
-
describe: i18n(`${i18nKey}.options.
|
|
359
|
-
type: '
|
|
374
|
+
yargs.option('local', {
|
|
375
|
+
describe: i18n(`${i18nKey}.options.local.describe`),
|
|
376
|
+
type: 'boolean',
|
|
377
|
+
hidden: true,
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
yargs.option('local-all', {
|
|
381
|
+
describe: i18n(`${i18nKey}.options.localAll.describe`),
|
|
382
|
+
type: 'boolean',
|
|
360
383
|
hidden: true,
|
|
361
384
|
});
|
|
362
385
|
|
|
@@ -7,6 +7,7 @@ const {
|
|
|
7
7
|
addUseEnvironmentOptions,
|
|
8
8
|
} = require('../../lib/commonOpts');
|
|
9
9
|
const { trackCommandUsage } = require('../../lib/usageTracking');
|
|
10
|
+
const { i18n } = require('../../lib/lang');
|
|
10
11
|
const {
|
|
11
12
|
logApiErrorInstance,
|
|
12
13
|
ApiErrorContext,
|
|
@@ -31,8 +32,10 @@ const {
|
|
|
31
32
|
const moment = require('moment');
|
|
32
33
|
const { promptUser } = require('../../lib/prompts/promptUtils');
|
|
33
34
|
|
|
35
|
+
const i18nKey = 'cli.commands.project.subcommands.listBuilds';
|
|
36
|
+
|
|
34
37
|
exports.command = 'list-builds [path]';
|
|
35
|
-
exports.describe =
|
|
38
|
+
exports.describe = i18n(`${i18nKey}.describe`);
|
|
36
39
|
|
|
37
40
|
exports.handler = async options => {
|
|
38
41
|
await loadAndValidateOptions(options);
|
|
@@ -16,6 +16,7 @@ const {
|
|
|
16
16
|
logFeedbackMessage,
|
|
17
17
|
validateProjectConfig,
|
|
18
18
|
pollProjectBuildAndDeploy,
|
|
19
|
+
showPlatformVersionWarning,
|
|
19
20
|
} = require('../../lib/projects');
|
|
20
21
|
const { i18n } = require('../../lib/lang');
|
|
21
22
|
const { getAccountConfig } = require('@hubspot/cli-lib');
|
|
@@ -48,6 +49,8 @@ exports.handler = async options => {
|
|
|
48
49
|
|
|
49
50
|
validateProjectConfig(projectConfig, projectDir);
|
|
50
51
|
|
|
52
|
+
await showPlatformVersionWarning(accountId, projectConfig);
|
|
53
|
+
|
|
51
54
|
await ensureProjectExists(accountId, projectConfig.name, { forceCreate });
|
|
52
55
|
|
|
53
56
|
try {
|
|
@@ -21,6 +21,7 @@ const {
|
|
|
21
21
|
pollDeployStatus,
|
|
22
22
|
validateProjectConfig,
|
|
23
23
|
logFeedbackMessage,
|
|
24
|
+
showPlatformVersionWarning,
|
|
24
25
|
} = require('../../lib/projects');
|
|
25
26
|
const {
|
|
26
27
|
cancelStagedBuild,
|
|
@@ -97,6 +98,8 @@ exports.handler = async options => {
|
|
|
97
98
|
|
|
98
99
|
validateProjectConfig(projectConfig, projectDir);
|
|
99
100
|
|
|
101
|
+
await showPlatformVersionWarning(accountId, projectConfig);
|
|
102
|
+
|
|
100
103
|
await ensureProjectExists(accountId, projectConfig.name);
|
|
101
104
|
|
|
102
105
|
try {
|
package/commands/project.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { addConfigOptions, addAccountOptions } = require('../lib/commonOpts');
|
|
2
|
+
const { i18n } = require('../lib/lang');
|
|
2
3
|
const deploy = require('./project/deploy');
|
|
3
4
|
const create = require('./project/create');
|
|
4
5
|
const upload = require('./project/upload');
|
|
@@ -10,24 +11,26 @@ const open = require('./project/open');
|
|
|
10
11
|
const dev = require('./project/dev');
|
|
11
12
|
const add = require('./project/add');
|
|
12
13
|
|
|
14
|
+
const i18nKey = 'cli.commands.project';
|
|
15
|
+
|
|
13
16
|
exports.command = 'project';
|
|
14
|
-
exports.describe =
|
|
17
|
+
exports.describe = i18n(`${i18nKey}.describe`);
|
|
15
18
|
|
|
16
19
|
exports.builder = yargs => {
|
|
17
20
|
addConfigOptions(yargs, true);
|
|
18
21
|
addAccountOptions(yargs, true);
|
|
19
22
|
|
|
20
23
|
// TODO: deploy must be updated
|
|
21
|
-
yargs.command(deploy).demandCommand(1, '');
|
|
22
24
|
yargs.command(create).demandCommand(0, '');
|
|
23
|
-
yargs.command(
|
|
25
|
+
yargs.command(add).demandCommand(0, '');
|
|
24
26
|
yargs.command(watch).demandCommand(0, '');
|
|
25
|
-
yargs.command(
|
|
27
|
+
yargs.command(dev).demandCommand(0, '');
|
|
28
|
+
yargs.command(upload).demandCommand(0, '');
|
|
29
|
+
yargs.command(deploy).demandCommand(1, '');
|
|
26
30
|
yargs.command(logs).demandCommand(1, '');
|
|
31
|
+
yargs.command(listBuilds).demandCommand(0, '');
|
|
27
32
|
yargs.command(download).demandCommand(0, '');
|
|
28
33
|
yargs.command(open).demandCommand(0, '');
|
|
29
|
-
yargs.command(dev).demandCommand(0, '');
|
|
30
|
-
yargs.command(add).demandCommand(0, '');
|
|
31
34
|
|
|
32
35
|
return yargs;
|
|
33
36
|
};
|
|
@@ -22,7 +22,10 @@ const {
|
|
|
22
22
|
} = require('../../lib/sandboxes');
|
|
23
23
|
const { getValidEnv } = require('@hubspot/cli-lib/lib/environment');
|
|
24
24
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
25
|
-
const {
|
|
25
|
+
const {
|
|
26
|
+
trackCommandUsage,
|
|
27
|
+
trackCommandMetadataUsage,
|
|
28
|
+
} = require('../../lib/usageTracking');
|
|
26
29
|
const {
|
|
27
30
|
sandboxTypePrompt,
|
|
28
31
|
sandboxNamePrompt,
|
|
@@ -153,6 +156,12 @@ exports.handler = async options => {
|
|
|
153
156
|
// Prompt user to sync assets after sandbox creation
|
|
154
157
|
const sandboxAccountConfig = getAccountConfig(result.sandbox.sandboxHubId);
|
|
155
158
|
const handleSyncSandbox = async syncTasks => {
|
|
159
|
+
// Send tracking event for secondary action, in this case a sandbox sync within the sandbox create flow
|
|
160
|
+
trackCommandMetadataUsage(
|
|
161
|
+
'sandbox-sync',
|
|
162
|
+
{ step: 'sandbox-create' },
|
|
163
|
+
result.sandbox.sandboxHubId
|
|
164
|
+
);
|
|
156
165
|
await syncSandbox({
|
|
157
166
|
accountConfig: sandboxAccountConfig,
|
|
158
167
|
parentAccountConfig: accountConfig,
|
|
@@ -168,19 +168,15 @@ exports.handler = async options => {
|
|
|
168
168
|
} catch (err) {
|
|
169
169
|
debugErrorAndContext(err);
|
|
170
170
|
|
|
171
|
-
if (err instanceof HubSpotAuthError) {
|
|
171
|
+
if (err instanceof HubSpotAuthError && err.statusCode === 401) {
|
|
172
172
|
// Intercept invalid key error
|
|
173
173
|
// This command uses the parent portal PAK to delete a sandbox, so we must specify which account needs a new key
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
account: getAccountName(parentAccount),
|
|
181
|
-
})
|
|
182
|
-
);
|
|
183
|
-
}
|
|
174
|
+
logger.log('');
|
|
175
|
+
logger.error(
|
|
176
|
+
i18n(`${i18nKey}.failure.invalidKey`, {
|
|
177
|
+
account: getAccountName(parentAccount),
|
|
178
|
+
})
|
|
179
|
+
);
|
|
184
180
|
} else if (
|
|
185
181
|
isSpecifiedError(err, {
|
|
186
182
|
statusCode: 403,
|
package/lang/en.lyaml
CHANGED
|
@@ -444,9 +444,10 @@ en:
|
|
|
444
444
|
describe: "Shortcut of the link you'd like to open"
|
|
445
445
|
selectLink: "Select a link to open"
|
|
446
446
|
project:
|
|
447
|
+
describe: "{{#bold}}[beta]{{/bold}} Commands for working with projects. For more information, visit our documentation: https://developers.hubspot.com/docs/platform/build-and-deploy-using-hubspot-projects"
|
|
447
448
|
subcommands:
|
|
448
449
|
dev:
|
|
449
|
-
describe: "Start local dev for the current project"
|
|
450
|
+
describe: "{{#bold}}[beta]{{/bold}} Start local dev for the current project"
|
|
450
451
|
logs:
|
|
451
452
|
betaMessage: "HubSpot projects local development"
|
|
452
453
|
nonSandboxWarning: "Testing in a sandbox is strongly recommended. To switch the target account, select an option below or run {{#bold}}`hs accounts use`{{/bold}} before running the command again."
|
|
@@ -461,17 +462,18 @@ en:
|
|
|
461
462
|
startupMessage: "Starting local dev server for {{#bold}}{{ projectName }}{{/bold}} ..."
|
|
462
463
|
prompt:
|
|
463
464
|
createProject: "Create new project {{ projectName}} in {{#bold}}[{{ accountIdentifier }}]{{/bold}}?"
|
|
464
|
-
targetNonSandbox: "Continue testing in a non-sandbox account?"
|
|
465
465
|
options:
|
|
466
|
-
|
|
467
|
-
describe: "
|
|
466
|
+
local:
|
|
467
|
+
describe: "Run the alpha version of this command with some local dev server functionality"
|
|
468
|
+
localAll:
|
|
469
|
+
describe: "Run the alpha version of this command with all local dev server functionality"
|
|
468
470
|
errors:
|
|
469
471
|
noProjectConfig: "No project detected. Please run this command again from a project directory."
|
|
470
472
|
projectLockedError: "Your project is locked. This may mean that another user is running the {{#bold}}`hs project dev`{{/bold}} command for this project. If this is you, unlock the project in Projects UI."
|
|
471
473
|
examples:
|
|
472
474
|
default: "Start local dev for the current project"
|
|
473
475
|
create:
|
|
474
|
-
describe: "Create a new project"
|
|
476
|
+
describe: "{{#bold}}[beta]{{/bold}} Create a new project"
|
|
475
477
|
logs:
|
|
476
478
|
welcomeMessage: "Welcome to HubSpot Developer Projects!"
|
|
477
479
|
examples:
|
|
@@ -486,7 +488,7 @@ en:
|
|
|
486
488
|
templateSource:
|
|
487
489
|
describe: "Path to custom GitHub repository from which to create project template"
|
|
488
490
|
add:
|
|
489
|
-
describe: "Create a new component within a project"
|
|
491
|
+
describe: "{{#bold}}[beta]{{/bold}} Create a new component within a project"
|
|
490
492
|
options:
|
|
491
493
|
name:
|
|
492
494
|
describe: "Component name"
|
|
@@ -501,7 +503,7 @@ en:
|
|
|
501
503
|
examples:
|
|
502
504
|
default: "Create a component within your project"
|
|
503
505
|
deploy:
|
|
504
|
-
describe: "Deploy a project build"
|
|
506
|
+
describe: "{{#bold}}[beta]{{/bold}} Deploy a project build"
|
|
505
507
|
debug:
|
|
506
508
|
deploying: "Deploying project at path: {{ path }}"
|
|
507
509
|
errors:
|
|
@@ -516,8 +518,10 @@ en:
|
|
|
516
518
|
describe: "Project build ID to be deployed"
|
|
517
519
|
project:
|
|
518
520
|
describe: "Project name"
|
|
521
|
+
listBuilds:
|
|
522
|
+
describe: "{{#bold}}[beta]{{/bold}} List the project's builds"
|
|
519
523
|
logs:
|
|
520
|
-
describe: "Get execution logs for a serverless function within a project"
|
|
524
|
+
describe: "{{#bold}}[beta]{{/bold}} Get execution logs for a serverless function within a project"
|
|
521
525
|
errors:
|
|
522
526
|
invalidAppName: "Could not find app with name \"{{ appName }}\" in project \"{{ projectName }}\""
|
|
523
527
|
logs:
|
|
@@ -552,7 +556,7 @@ en:
|
|
|
552
556
|
endpoint:
|
|
553
557
|
describe: "Public endpoint path"
|
|
554
558
|
upload:
|
|
555
|
-
describe: "Upload your project files and create a new build"
|
|
559
|
+
describe: "{{#bold}}[beta]{{/bold}} Upload your project files and create a new build"
|
|
556
560
|
examples:
|
|
557
561
|
default: "Upload a project"
|
|
558
562
|
logs:
|
|
@@ -570,7 +574,7 @@ en:
|
|
|
570
574
|
path:
|
|
571
575
|
describe: "Path to a project folder"
|
|
572
576
|
watch:
|
|
573
|
-
describe: "Watch your local project for changes and automatically upload changed files to a new build in HubSpot"
|
|
577
|
+
describe: "{{#bold}}[beta]{{/bold}} Watch your local project for changes and automatically upload changed files to a new build in HubSpot"
|
|
574
578
|
examples:
|
|
575
579
|
default: "Watch a project within the myProjectFolder folder"
|
|
576
580
|
logs:
|
|
@@ -582,7 +586,7 @@ en:
|
|
|
582
586
|
initialUpload:
|
|
583
587
|
describe: "Upload directory before watching for updates"
|
|
584
588
|
download:
|
|
585
|
-
describe: "Download your project files from HubSpot and write to a path on your computer"
|
|
589
|
+
describe: "{{#bold}}[beta]{{/bold}} Download your project files from HubSpot and write to a path on your computer"
|
|
586
590
|
examples:
|
|
587
591
|
default: "Download the project myProject into myProjectFolder folder"
|
|
588
592
|
logs:
|
|
@@ -599,7 +603,7 @@ en:
|
|
|
599
603
|
dest:
|
|
600
604
|
describe: "Destination folder for the project"
|
|
601
605
|
open:
|
|
602
|
-
describe: "Open
|
|
606
|
+
describe: "{{#bold}}[beta]{{/bold}} Open the specified project's details page in the browser"
|
|
603
607
|
options:
|
|
604
608
|
project:
|
|
605
609
|
describe: "Name of project to open"
|
|
@@ -848,8 +852,12 @@ en:
|
|
|
848
852
|
lib:
|
|
849
853
|
DevServerManager:
|
|
850
854
|
portConflict: "The port {{ port }} is already in use."
|
|
855
|
+
notInitialized: "The Dev Server Manager must be initialized before it is started."
|
|
856
|
+
noCompatibleComponents: "Skipping call to {{ serverKey }} because there are no compatible components in the project."
|
|
851
857
|
LocalDevManagerV2:
|
|
852
858
|
failedToInitialize: "Missing required arguments to initialize Local Dev"
|
|
859
|
+
noComponents: "There are no components in this project."
|
|
860
|
+
noRunnableComponents: "There are no components in this project that support local development."
|
|
853
861
|
betaMessage: "HubSpot projects local development"
|
|
854
862
|
running: "Running {{#bold}}{{ projectName }}{{/bold}} locally on {{ accountIdentifier }}, waiting for changes ..."
|
|
855
863
|
quitHelper: "Press {{#bold}}'q'{{/bold}} to stop the local dev server"
|
|
@@ -857,8 +865,16 @@ en:
|
|
|
857
865
|
exitingStart: "Stopping local dev server ..."
|
|
858
866
|
exitingSucceed: "Successfully exited"
|
|
859
867
|
exitingFail: "Failed to cleanup before exiting"
|
|
868
|
+
uploadWarning:
|
|
869
|
+
missingComponents: "Your deployed project does not contain the components {{#bold}}'{{ missingComponents }}'{{/bold}}. This may cause issues in local development."
|
|
870
|
+
header: "{{ reason }} To reflect these changes:"
|
|
871
|
+
stopDev: " * Stop {{#bold}}`hs project dev`{{/bold}}"
|
|
872
|
+
runUpload: " * Run {{#bold}}`hs project upload`{{/bold}}"
|
|
873
|
+
runUploadWithAccount: " * Run {{#bold}}`hs project upload --account={{ accountId }}`{{/bold}}"
|
|
874
|
+
restartDev: " * Re-run {{#bold}}`hs project dev`{{/bold}}"
|
|
860
875
|
devServer:
|
|
861
876
|
cleanupError: "Failed to cleanup local dev server: {{ message }}"
|
|
877
|
+
setupError: "Failed to setup local dev server: {{ message }}"
|
|
862
878
|
startError: "Failed to start local dev server: {{ message }}"
|
|
863
879
|
LocalDevManager:
|
|
864
880
|
failedToInitialize: "Missing required arguments to initialize Local Dev Manager"
|
|
@@ -925,6 +941,9 @@ en:
|
|
|
925
941
|
logFeedbackMessage:
|
|
926
942
|
feedbackHeader: "We'd love to hear your feedback!"
|
|
927
943
|
feedbackMessage: "How are you liking the new projects and developer tools? \n > Run `{{#yellow}}hs feedback{{/yellow}}` to let us know what you think!\n"
|
|
944
|
+
showPlatformVersionWarning:
|
|
945
|
+
noPlatformVersion: "No platformVersion found in hsproject.json. Falling back to version \"{{ defaultVersion }}\"."
|
|
946
|
+
noPlatformVersionAlt: "No platformVersion found in hsproject.json. Falling back to default version."
|
|
928
947
|
ui:
|
|
929
948
|
betaTag: "{{#bold}}[beta]{{/bold}}"
|
|
930
949
|
betaWarning:
|
package/lib/DevServerManager.js
CHANGED
|
@@ -1,28 +1,39 @@
|
|
|
1
1
|
const express = require('express');
|
|
2
2
|
const bodyParser = require('body-parser');
|
|
3
3
|
const cors = require('cors');
|
|
4
|
-
const
|
|
4
|
+
const httpClient = require('@hubspot/cli-lib/http');
|
|
5
|
+
const { logger } = require('@hubspot/cli-lib/logger');
|
|
5
6
|
const { getProjectDetailUrl } = require('./projects');
|
|
7
|
+
const { COMPONENT_TYPES } = require('./projectStructure');
|
|
6
8
|
const { i18n } = require('./lang');
|
|
7
9
|
const { EXIT_CODES } = require('./enums/exitCodes');
|
|
8
|
-
const {
|
|
10
|
+
const { promptUser } = require('./prompts/promptUtils');
|
|
9
11
|
|
|
10
12
|
const i18nKey = 'cli.lib.DevServerManager';
|
|
11
13
|
|
|
12
14
|
const DEFAULT_PORT = 8080;
|
|
15
|
+
const SERVER_KEYS = {
|
|
16
|
+
app: 'app',
|
|
17
|
+
};
|
|
13
18
|
|
|
14
19
|
class DevServerManager {
|
|
15
20
|
constructor() {
|
|
16
21
|
this.initialized = false;
|
|
22
|
+
this.started = false;
|
|
23
|
+
this.componentsByType = {};
|
|
17
24
|
this.server = null;
|
|
18
25
|
this.path = null;
|
|
19
26
|
this.devServers = {};
|
|
27
|
+
this.debug = false;
|
|
20
28
|
}
|
|
21
29
|
|
|
22
30
|
safeLoadServer() {
|
|
23
31
|
try {
|
|
24
32
|
const { DevModeInterface } = require('@hubspot/ui-extensions-dev-server');
|
|
25
|
-
this.devServers[
|
|
33
|
+
this.devServers[SERVER_KEYS.app] = {
|
|
34
|
+
componentType: COMPONENT_TYPES.app,
|
|
35
|
+
serverInterface: DevModeInterface,
|
|
36
|
+
};
|
|
26
37
|
} catch (e) {
|
|
27
38
|
logger.debug('Failed to load dev server interface: ', e);
|
|
28
39
|
}
|
|
@@ -33,8 +44,16 @@ class DevServerManager {
|
|
|
33
44
|
|
|
34
45
|
for (let i = 0; i < serverKeys.length; i++) {
|
|
35
46
|
const serverKey = serverKeys[i];
|
|
36
|
-
const
|
|
37
|
-
|
|
47
|
+
const devServer = this.devServers[serverKey];
|
|
48
|
+
|
|
49
|
+
const compatibleComponents =
|
|
50
|
+
this.componentsByType[devServer.componentType] || {};
|
|
51
|
+
|
|
52
|
+
if (Object.keys(compatibleComponents).length) {
|
|
53
|
+
await callback(devServer.serverInterface, compatibleComponents);
|
|
54
|
+
} else {
|
|
55
|
+
logger.debug(i18n(`${i18nKey}.noCompatibleComponents`, { serverKey }));
|
|
56
|
+
}
|
|
38
57
|
}
|
|
39
58
|
}
|
|
40
59
|
|
|
@@ -42,66 +61,98 @@ class DevServerManager {
|
|
|
42
61
|
return this.path ? `${this.path}/${path}` : null;
|
|
43
62
|
}
|
|
44
63
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
projectConfig,
|
|
50
|
-
projectSourceDir,
|
|
51
|
-
}) {
|
|
52
|
-
const app = express();
|
|
53
|
-
|
|
54
|
-
// Install Middleware
|
|
55
|
-
app.use(bodyParser.json({ limit: '50mb' }));
|
|
56
|
-
app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));
|
|
57
|
-
app.use(cors());
|
|
58
|
-
|
|
59
|
-
// Configure
|
|
60
|
-
app.set('trust proxy', true);
|
|
61
|
-
|
|
62
|
-
// Initialize a base route
|
|
63
|
-
app.get('/', (req, res) => {
|
|
64
|
-
res.send('HubSpot local dev server');
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
// Initialize URL redirects
|
|
68
|
-
app.get('/hs/project', (req, res) => {
|
|
69
|
-
res.redirect(getProjectDetailUrl(projectConfig.name, accountId));
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
// Start server
|
|
73
|
-
this.server = await app.listen(DEFAULT_PORT).on('error', err => {
|
|
74
|
-
if (err.code === 'EADDRINUSE') {
|
|
75
|
-
logger.error(i18n(`${i18nKey}.portConflict`, { port: DEFAULT_PORT }));
|
|
76
|
-
logger.log();
|
|
77
|
-
process.exit(EXIT_CODES.ERROR);
|
|
64
|
+
arrangeComponentsByType(components) {
|
|
65
|
+
return components.reduce((acc, component) => {
|
|
66
|
+
if (!acc[component.type]) {
|
|
67
|
+
acc[component.type] = {};
|
|
78
68
|
}
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
const projectFiles = await walk(projectSourceDir);
|
|
82
|
-
|
|
83
|
-
// Initialize component servers
|
|
84
|
-
await this.iterateDevServers(async serverInterface => {
|
|
85
|
-
if (serverInterface.start) {
|
|
86
|
-
await serverInterface.start({
|
|
87
|
-
accountId,
|
|
88
|
-
debug,
|
|
89
|
-
extension,
|
|
90
|
-
projectConfig,
|
|
91
|
-
projectFiles,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
69
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
70
|
+
acc[component.type][component.config.name] = component;
|
|
71
|
+
|
|
72
|
+
return acc;
|
|
73
|
+
}, {});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async setup({ alpha, components, debug, onUploadRequired }) {
|
|
77
|
+
this.debug = debug;
|
|
78
|
+
|
|
79
|
+
this.componentsByType = this.arrangeComponentsByType(components);
|
|
80
|
+
|
|
81
|
+
this.safeLoadServer();
|
|
82
|
+
|
|
83
|
+
await this.iterateDevServers(
|
|
84
|
+
async (serverInterface, compatibleComponents) => {
|
|
85
|
+
if (serverInterface.setup) {
|
|
86
|
+
await serverInterface.setup({
|
|
87
|
+
alpha,
|
|
88
|
+
components: compatibleComponents,
|
|
89
|
+
debug,
|
|
90
|
+
onUploadRequired,
|
|
91
|
+
promptUser,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
);
|
|
99
96
|
|
|
100
97
|
this.initialized = true;
|
|
101
98
|
}
|
|
102
99
|
|
|
103
|
-
async
|
|
100
|
+
async start({ alpha, accountId, projectConfig }) {
|
|
104
101
|
if (this.initialized) {
|
|
102
|
+
const app = express();
|
|
103
|
+
|
|
104
|
+
// Install Middleware
|
|
105
|
+
app.use(bodyParser.json({ limit: '50mb' }));
|
|
106
|
+
app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));
|
|
107
|
+
app.use(cors());
|
|
108
|
+
|
|
109
|
+
// Configure
|
|
110
|
+
app.set('trust proxy', true);
|
|
111
|
+
|
|
112
|
+
// Initialize a base route
|
|
113
|
+
app.get('/', (req, res) => {
|
|
114
|
+
res.send('HubSpot local dev server');
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Initialize URL redirects
|
|
118
|
+
app.get('/hs/project', (req, res) => {
|
|
119
|
+
res.redirect(getProjectDetailUrl(projectConfig.name, accountId));
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Start server
|
|
123
|
+
this.server = await app.listen(DEFAULT_PORT).on('error', err => {
|
|
124
|
+
if (err.code === 'EADDRINUSE') {
|
|
125
|
+
logger.error(i18n(`${i18nKey}.portConflict`, { port: DEFAULT_PORT }));
|
|
126
|
+
logger.log();
|
|
127
|
+
process.exit(EXIT_CODES.ERROR);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Initialize component servers
|
|
132
|
+
await this.iterateDevServers(async serverInterface => {
|
|
133
|
+
if (serverInterface.start) {
|
|
134
|
+
await serverInterface.start({
|
|
135
|
+
alpha,
|
|
136
|
+
accountId,
|
|
137
|
+
debug: this.debug,
|
|
138
|
+
httpClient,
|
|
139
|
+
projectConfig,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
this.path = this.server.address()
|
|
145
|
+
? `http://localhost:${this.server.address().port}`
|
|
146
|
+
: null;
|
|
147
|
+
} else {
|
|
148
|
+
throw new Error(i18n(`${i18nKey}.notInitialized`));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
this.started = true;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async cleanup() {
|
|
155
|
+
if (this.started) {
|
|
105
156
|
await this.iterateDevServers(async serverInterface => {
|
|
106
157
|
if (serverInterface.cleanup) {
|
|
107
158
|
await serverInterface.cleanup();
|
package/lib/LocalDevManager.js
CHANGED
|
@@ -303,7 +303,8 @@ class LocalDevManager {
|
|
|
303
303
|
try {
|
|
304
304
|
const { buildId } = await provisionBuild(
|
|
305
305
|
this.targetAccountId,
|
|
306
|
-
this.projectConfig.name
|
|
306
|
+
this.projectConfig.name,
|
|
307
|
+
this.projectConfig.platformVersion
|
|
307
308
|
);
|
|
308
309
|
this.currentStagedBuildId = buildId;
|
|
309
310
|
} catch (err) {
|
|
@@ -536,7 +537,11 @@ class LocalDevManager {
|
|
|
536
537
|
let queueBuildError;
|
|
537
538
|
|
|
538
539
|
try {
|
|
539
|
-
await queueBuild(
|
|
540
|
+
await queueBuild(
|
|
541
|
+
this.targetAccountId,
|
|
542
|
+
this.projectConfig.name,
|
|
543
|
+
this.projectConfig.platformVersion
|
|
544
|
+
);
|
|
540
545
|
} catch (err) {
|
|
541
546
|
queueBuildError = err;
|
|
542
547
|
}
|
|
@@ -663,6 +668,9 @@ class LocalDevManager {
|
|
|
663
668
|
|
|
664
669
|
async devServerStart() {
|
|
665
670
|
try {
|
|
671
|
+
// Set this to true manually for now
|
|
672
|
+
DevServerManager.initialized = true;
|
|
673
|
+
|
|
666
674
|
await DevServerManager.start({
|
|
667
675
|
accountId: this.targetAccountId,
|
|
668
676
|
debug: this.debug,
|
package/lib/LocalDevManagerV2.js
CHANGED
|
@@ -3,11 +3,26 @@ const chalk = require('chalk');
|
|
|
3
3
|
const { i18n } = require('./lang');
|
|
4
4
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
5
5
|
const { handleKeypress } = require('@hubspot/cli-lib/lib/process');
|
|
6
|
+
const {
|
|
7
|
+
getAccountId,
|
|
8
|
+
getConfigDefaultAccount,
|
|
9
|
+
} = require('@hubspot/cli-lib/lib/config');
|
|
6
10
|
const SpinniesManager = require('./SpinniesManager');
|
|
7
11
|
const DevServerManager = require('./DevServerManager');
|
|
8
12
|
const { EXIT_CODES } = require('./enums/exitCodes');
|
|
9
13
|
const { getProjectDetailUrl } = require('./projects');
|
|
10
|
-
const {
|
|
14
|
+
const {
|
|
15
|
+
COMPONENT_TYPES,
|
|
16
|
+
findProjectComponents,
|
|
17
|
+
getAppCardConfigs,
|
|
18
|
+
} = require('./projectStructure');
|
|
19
|
+
const {
|
|
20
|
+
UI_COLORS,
|
|
21
|
+
uiAccountDescription,
|
|
22
|
+
uiBetaMessage,
|
|
23
|
+
uiLink,
|
|
24
|
+
uiLine,
|
|
25
|
+
} = require('./ui');
|
|
11
26
|
|
|
12
27
|
const i18nKey = 'cli.lib.LocalDevManagerV2';
|
|
13
28
|
|
|
@@ -16,8 +31,9 @@ class LocalDevManagerV2 {
|
|
|
16
31
|
this.targetAccountId = options.targetAccountId;
|
|
17
32
|
this.projectConfig = options.projectConfig;
|
|
18
33
|
this.projectDir = options.projectDir;
|
|
19
|
-
this.extension = options.extension;
|
|
20
34
|
this.debug = options.debug || false;
|
|
35
|
+
this.alpha = options.alpha;
|
|
36
|
+
this.deployedBuild = options.deployedBuild;
|
|
21
37
|
|
|
22
38
|
this.projectSourceDir = path.join(
|
|
23
39
|
this.projectDir,
|
|
@@ -31,14 +47,38 @@ class LocalDevManagerV2 {
|
|
|
31
47
|
}
|
|
32
48
|
|
|
33
49
|
async start() {
|
|
34
|
-
console.clear();
|
|
35
50
|
SpinniesManager.removeAll();
|
|
36
51
|
SpinniesManager.init();
|
|
37
52
|
|
|
53
|
+
const components = await findProjectComponents(this.projectSourceDir);
|
|
54
|
+
|
|
55
|
+
if (!components.length) {
|
|
56
|
+
logger.log();
|
|
57
|
+
logger.error(i18n(`${i18nKey}.noComponents`));
|
|
58
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const runnableComponents = components.filter(
|
|
62
|
+
component => component.runnable
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
if (!runnableComponents.length) {
|
|
66
|
+
logger.log();
|
|
67
|
+
logger.error(i18n(`${i18nKey}.noRunnableComponents`));
|
|
68
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
logger.log();
|
|
72
|
+
const setupSucceeded = await this.devServerSetup(runnableComponents);
|
|
73
|
+
|
|
74
|
+
if (setupSucceeded || !this.debug) {
|
|
75
|
+
console.clear();
|
|
76
|
+
}
|
|
77
|
+
|
|
38
78
|
uiBetaMessage(i18n(`${i18nKey}.betaMessage`));
|
|
39
79
|
logger.log();
|
|
40
80
|
logger.log(
|
|
41
|
-
chalk.hex(
|
|
81
|
+
chalk.hex(UI_COLORS.orange)(
|
|
42
82
|
i18n(`${i18nKey}.running`, {
|
|
43
83
|
accountIdentifier: uiAccountDescription(this.targetAccountId),
|
|
44
84
|
projectName: this.projectConfig.name,
|
|
@@ -59,6 +99,8 @@ class LocalDevManagerV2 {
|
|
|
59
99
|
await this.devServerStart();
|
|
60
100
|
|
|
61
101
|
this.updateKeypressListeners();
|
|
102
|
+
|
|
103
|
+
this.compareLocalProjectToDeployed(runnableComponents);
|
|
62
104
|
}
|
|
63
105
|
|
|
64
106
|
async stop() {
|
|
@@ -89,15 +131,83 @@ class LocalDevManagerV2 {
|
|
|
89
131
|
});
|
|
90
132
|
}
|
|
91
133
|
|
|
134
|
+
logUploadWarning(reason) {
|
|
135
|
+
const currentDefaultAccount = getConfigDefaultAccount();
|
|
136
|
+
const defaultAccountId = getAccountId(currentDefaultAccount);
|
|
137
|
+
|
|
138
|
+
logger.log();
|
|
139
|
+
logger.warn(i18n(`${i18nKey}.uploadWarning.header`, { reason }));
|
|
140
|
+
logger.log(i18n(`${i18nKey}.uploadWarning.stopDev`));
|
|
141
|
+
if (this.targetAccountId !== defaultAccountId) {
|
|
142
|
+
logger.log(
|
|
143
|
+
i18n(`${i18nKey}.uploadWarning.runUploadWithAccount`, {
|
|
144
|
+
accountId: this.targetAccountId,
|
|
145
|
+
})
|
|
146
|
+
);
|
|
147
|
+
} else {
|
|
148
|
+
logger.log(i18n(`${i18nKey}.uploadWarning.runUpload`));
|
|
149
|
+
}
|
|
150
|
+
logger.log(i18n(`${i18nKey}.uploadWarning.restartDev`));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
compareLocalProjectToDeployed(runnableComponents) {
|
|
154
|
+
const deployedComponentNames = this.deployedBuild.subbuildStatuses.map(
|
|
155
|
+
subbuildStatus => subbuildStatus.buildName
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
let missingComponents = [];
|
|
159
|
+
|
|
160
|
+
runnableComponents.forEach(({ type, config, path }) => {
|
|
161
|
+
if (type === COMPONENT_TYPES.app) {
|
|
162
|
+
const cardConfigs = getAppCardConfigs(config, path);
|
|
163
|
+
|
|
164
|
+
cardConfigs.forEach(cardConfig => {
|
|
165
|
+
if (
|
|
166
|
+
cardConfig.data &&
|
|
167
|
+
cardConfig.data.title &&
|
|
168
|
+
!deployedComponentNames.includes(cardConfig.data.title)
|
|
169
|
+
) {
|
|
170
|
+
missingComponents.push(cardConfig.data.title);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
if (missingComponents.length) {
|
|
177
|
+
this.logUploadWarning(
|
|
178
|
+
i18n(`${i18nKey}.uploadWarning.missingComponents`, {
|
|
179
|
+
missingComponents: missingComponents.join(','),
|
|
180
|
+
})
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async devServerSetup(components) {
|
|
186
|
+
try {
|
|
187
|
+
await DevServerManager.setup({
|
|
188
|
+
alpha: this.alpha,
|
|
189
|
+
components,
|
|
190
|
+
debug: this.debug,
|
|
191
|
+
onUploadRequired: this.logUploadWarning.bind(this),
|
|
192
|
+
});
|
|
193
|
+
return true;
|
|
194
|
+
} catch (e) {
|
|
195
|
+
if (this.debug) {
|
|
196
|
+
logger.error(e);
|
|
197
|
+
}
|
|
198
|
+
logger.error(
|
|
199
|
+
i18n(`${i18nKey}.devServer.setupError`, { message: e.message })
|
|
200
|
+
);
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
92
205
|
async devServerStart() {
|
|
93
206
|
try {
|
|
94
|
-
DevServerManager.safeLoadServer();
|
|
95
207
|
await DevServerManager.start({
|
|
208
|
+
alpha: this.alpha,
|
|
96
209
|
accountId: this.targetAccountId,
|
|
97
|
-
debug: this.debug,
|
|
98
|
-
extension: this.extension,
|
|
99
210
|
projectConfig: this.projectConfig,
|
|
100
|
-
projectSourceDir: this.projectSourceDir,
|
|
101
211
|
});
|
|
102
212
|
} catch (e) {
|
|
103
213
|
if (this.debug) {
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { walk } = require('@hubspot/cli-lib/lib/walk');
|
|
4
|
+
const { logger } = require('@hubspot/cli-lib/logger');
|
|
5
|
+
|
|
6
|
+
const COMPONENT_TYPES = Object.freeze({
|
|
7
|
+
app: 'app',
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const APP_COMPONENT_CONFIG = 'app.json';
|
|
11
|
+
|
|
12
|
+
function loadConfigFile(configPath) {
|
|
13
|
+
if (configPath) {
|
|
14
|
+
try {
|
|
15
|
+
const source = fs.readFileSync(configPath);
|
|
16
|
+
const parsedConfig = JSON.parse(source);
|
|
17
|
+
return parsedConfig;
|
|
18
|
+
} catch (e) {
|
|
19
|
+
logger.debug(e);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getAppCardConfigs(appConfig, appPath) {
|
|
26
|
+
let cardConfigs = [];
|
|
27
|
+
let cards;
|
|
28
|
+
|
|
29
|
+
if (appConfig && appConfig.extensions && appConfig.extensions.crm) {
|
|
30
|
+
cards = appConfig.extensions.crm.cards;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (cards) {
|
|
34
|
+
cards.forEach(({ file }) => {
|
|
35
|
+
const cardConfigPath = path.join(appPath, file);
|
|
36
|
+
const cardConfig = loadConfigFile(cardConfigPath);
|
|
37
|
+
|
|
38
|
+
if (cardConfig) {
|
|
39
|
+
cardConfigs.push(cardConfig);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return cardConfigs;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function getIsLegacyApp(appConfig, appPath) {
|
|
48
|
+
const cardConfigs = getAppCardConfigs(appConfig, appPath);
|
|
49
|
+
|
|
50
|
+
if (!cardConfigs.length) {
|
|
51
|
+
// Assume any app that does not have any cards is not legacy
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let hasAnyReactExtensions = false;
|
|
56
|
+
|
|
57
|
+
cardConfigs.forEach(cardConfig => {
|
|
58
|
+
if (!hasAnyReactExtensions) {
|
|
59
|
+
const isReactExtension =
|
|
60
|
+
cardConfig &&
|
|
61
|
+
!!cardConfig.data &&
|
|
62
|
+
!!cardConfig.data.module &&
|
|
63
|
+
!!cardConfig.data.module.file;
|
|
64
|
+
|
|
65
|
+
hasAnyReactExtensions = isReactExtension;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
return !hasAnyReactExtensions;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function findProjectComponents(projectSourceDir) {
|
|
73
|
+
const components = [];
|
|
74
|
+
|
|
75
|
+
const projectFiles = await walk(projectSourceDir);
|
|
76
|
+
|
|
77
|
+
projectFiles.forEach(projectFile => {
|
|
78
|
+
// Find app components
|
|
79
|
+
if (projectFile.endsWith(APP_COMPONENT_CONFIG)) {
|
|
80
|
+
const parsedAppConfig = loadConfigFile(projectFile);
|
|
81
|
+
|
|
82
|
+
if (parsedAppConfig && parsedAppConfig.name) {
|
|
83
|
+
const appPath = projectFile.substring(
|
|
84
|
+
0,
|
|
85
|
+
projectFile.indexOf(APP_COMPONENT_CONFIG)
|
|
86
|
+
);
|
|
87
|
+
const isLegacy = getIsLegacyApp(parsedAppConfig, appPath);
|
|
88
|
+
|
|
89
|
+
components.push({
|
|
90
|
+
type: COMPONENT_TYPES.app,
|
|
91
|
+
config: parsedAppConfig,
|
|
92
|
+
runnable: !isLegacy,
|
|
93
|
+
path: appPath,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return components;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = {
|
|
103
|
+
COMPONENT_TYPES,
|
|
104
|
+
findProjectComponents,
|
|
105
|
+
getAppCardConfigs,
|
|
106
|
+
};
|
package/lib/projects.js
CHANGED
|
@@ -17,6 +17,9 @@ const {
|
|
|
17
17
|
PROJECT_TASK_TYPES,
|
|
18
18
|
SPINNER_STATUS,
|
|
19
19
|
} = require('@hubspot/cli-lib/lib/constants');
|
|
20
|
+
const {
|
|
21
|
+
fetchDefaultVersion,
|
|
22
|
+
} = require('@hubspot/cli-lib/lib/projectPlatformVersion');
|
|
20
23
|
const {
|
|
21
24
|
createProject,
|
|
22
25
|
getBuildStatus,
|
|
@@ -312,7 +315,8 @@ const uploadProjectFiles = async (
|
|
|
312
315
|
accountId,
|
|
313
316
|
projectName,
|
|
314
317
|
filePath,
|
|
315
|
-
uploadMessage
|
|
318
|
+
uploadMessage,
|
|
319
|
+
platformVersion
|
|
316
320
|
) => {
|
|
317
321
|
SpinniesManager.init({});
|
|
318
322
|
const accountIdentifier = uiAccountDescription(accountId);
|
|
@@ -333,7 +337,8 @@ const uploadProjectFiles = async (
|
|
|
333
337
|
accountId,
|
|
334
338
|
projectName,
|
|
335
339
|
filePath,
|
|
336
|
-
uploadMessage
|
|
340
|
+
uploadMessage,
|
|
341
|
+
platformVersion
|
|
337
342
|
);
|
|
338
343
|
|
|
339
344
|
buildId = upload.buildId;
|
|
@@ -490,7 +495,8 @@ const handleProjectUpload = async (
|
|
|
490
495
|
accountId,
|
|
491
496
|
projectConfig.name,
|
|
492
497
|
tempFile.name,
|
|
493
|
-
uploadMessage
|
|
498
|
+
uploadMessage,
|
|
499
|
+
projectConfig.platformVersion
|
|
494
500
|
);
|
|
495
501
|
|
|
496
502
|
if (error) {
|
|
@@ -807,6 +813,28 @@ const createProjectComponent = async (component, name) => {
|
|
|
807
813
|
);
|
|
808
814
|
};
|
|
809
815
|
|
|
816
|
+
const showPlatformVersionWarning = async (accountId, projectConfig) => {
|
|
817
|
+
const platformVersion = projectConfig.platformVersion;
|
|
818
|
+
|
|
819
|
+
if (!platformVersion) {
|
|
820
|
+
try {
|
|
821
|
+
const defaultVersion = await fetchDefaultVersion(accountId);
|
|
822
|
+
logger.log('');
|
|
823
|
+
logger.warn(
|
|
824
|
+
i18n(`${i18nKey}.showPlatformVersionWarning.noPlatformVersion`, {
|
|
825
|
+
defaultVersion,
|
|
826
|
+
})
|
|
827
|
+
);
|
|
828
|
+
} catch (e) {
|
|
829
|
+
logger.log('');
|
|
830
|
+
logger.warn(
|
|
831
|
+
i18n(`${i18nKey}.showPlatformVersionWarning.noPlatformVersionAlt`)
|
|
832
|
+
);
|
|
833
|
+
logger.debug(e.error);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
};
|
|
837
|
+
|
|
810
838
|
module.exports = {
|
|
811
839
|
writeProjectConfig,
|
|
812
840
|
getProjectConfig,
|
|
@@ -823,4 +851,5 @@ module.exports = {
|
|
|
823
851
|
ensureProjectExists,
|
|
824
852
|
logFeedbackMessage,
|
|
825
853
|
createProjectComponent,
|
|
854
|
+
showPlatformVersionWarning,
|
|
826
855
|
};
|
package/lib/ui.js
CHANGED
|
@@ -6,6 +6,10 @@ const { getAccountConfig } = require('@hubspot/cli-lib/lib/config');
|
|
|
6
6
|
const { i18n } = require('./lang');
|
|
7
7
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
8
8
|
|
|
9
|
+
const UI_COLORS = {
|
|
10
|
+
orange: '#FF8F59',
|
|
11
|
+
};
|
|
12
|
+
|
|
9
13
|
/**
|
|
10
14
|
* Outputs horizontal line
|
|
11
15
|
*
|
|
@@ -108,7 +112,7 @@ const uiFeatureHighlight = (commands, title) => {
|
|
|
108
112
|
const uiBetaMessage = message => {
|
|
109
113
|
const i18nKey = 'cli.lib.ui';
|
|
110
114
|
|
|
111
|
-
logger.log(chalk.hex(
|
|
115
|
+
logger.log(chalk.hex(UI_COLORS.orange)(i18n(`${i18nKey}.betaTag`)), message);
|
|
112
116
|
};
|
|
113
117
|
|
|
114
118
|
const uiBetaWarning = logMessage => {
|
|
@@ -120,6 +124,7 @@ const uiBetaWarning = logMessage => {
|
|
|
120
124
|
};
|
|
121
125
|
|
|
122
126
|
module.exports = {
|
|
127
|
+
UI_COLORS,
|
|
123
128
|
uiAccountDescription,
|
|
124
129
|
uiBetaMessage,
|
|
125
130
|
uiBetaWarning,
|
package/lib/usageTracking.js
CHANGED
|
@@ -7,6 +7,25 @@ const { version } = require('../package.json');
|
|
|
7
7
|
const { getPlatform } = require('./environment');
|
|
8
8
|
const { setLogLevel } = require('./commonOpts');
|
|
9
9
|
|
|
10
|
+
/* **
|
|
11
|
+
Available tracking meta properties
|
|
12
|
+
|
|
13
|
+
- action: "The specific action taken in the CLI"
|
|
14
|
+
- os: "The user's OS"
|
|
15
|
+
- nodeVersion: "The user's version of node.js"
|
|
16
|
+
- nodeMajorVersion: "The user's major version of node.js"
|
|
17
|
+
- version: "The user's version of the CLI"
|
|
18
|
+
- command: "The specific command that the user ran in this interaction"
|
|
19
|
+
- authType: "The configured auth type the user has for the CLI"
|
|
20
|
+
- step: "The specific step in the auth process"
|
|
21
|
+
- assetType: "The CMS asset type"
|
|
22
|
+
- mode: "The CLI mode (draft or publish"
|
|
23
|
+
- type: "The upload type (file or folder)"
|
|
24
|
+
- file: "Whether or not the 'file' flag was used"
|
|
25
|
+
- successful: "Whether or not the CLI interaction was successful"
|
|
26
|
+
|
|
27
|
+
*/
|
|
28
|
+
|
|
10
29
|
const EventClass = {
|
|
11
30
|
USAGE: 'USAGE',
|
|
12
31
|
INTERACTION: 'INTERACTION',
|
|
@@ -132,10 +151,48 @@ const trackAuthAction = async (command, authType, step, accountId) => {
|
|
|
132
151
|
}
|
|
133
152
|
};
|
|
134
153
|
|
|
154
|
+
function trackCommandMetadataUsage(command, meta = {}, accountId) {
|
|
155
|
+
if (!isTrackingAllowed()) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
logger.debug('Attempting to track metadata usage of "%s" command', command);
|
|
159
|
+
let authType = 'unknown';
|
|
160
|
+
if (accountId) {
|
|
161
|
+
const accountConfig = getAccountConfig(accountId);
|
|
162
|
+
authType =
|
|
163
|
+
accountConfig && accountConfig.authType
|
|
164
|
+
? accountConfig.authType
|
|
165
|
+
: API_KEY_AUTH_METHOD.value;
|
|
166
|
+
}
|
|
167
|
+
setImmediate(async () => {
|
|
168
|
+
const usageTrackingEvent = {
|
|
169
|
+
action: 'cli-command-metadata',
|
|
170
|
+
os: getPlatform(),
|
|
171
|
+
...getNodeVersionData(),
|
|
172
|
+
version,
|
|
173
|
+
command,
|
|
174
|
+
authType,
|
|
175
|
+
...meta,
|
|
176
|
+
};
|
|
177
|
+
try {
|
|
178
|
+
await trackUsage(
|
|
179
|
+
'cli-interaction',
|
|
180
|
+
EventClass.INTERACTION,
|
|
181
|
+
usageTrackingEvent,
|
|
182
|
+
accountId
|
|
183
|
+
);
|
|
184
|
+
logger.debug('Sent usage tracking command event: %o', usageTrackingEvent);
|
|
185
|
+
} catch (e) {
|
|
186
|
+
logger.debug('Metadata usage tracking failed: %s', e.message);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
135
191
|
module.exports = {
|
|
136
192
|
trackCommandUsage,
|
|
137
193
|
trackHelpUsage,
|
|
138
194
|
addHelpUsageTracking,
|
|
139
195
|
trackConvertFieldsUsage,
|
|
140
196
|
trackAuthAction,
|
|
197
|
+
trackCommandMetadataUsage,
|
|
141
198
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "4.2.1-beta.
|
|
3
|
+
"version": "4.2.1-beta.2",
|
|
4
4
|
"description": "CLI for working with HubSpot",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
"url": "https://github.com/HubSpot/hubspot-cms-tools"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@hubspot/cli-lib": "^4.1
|
|
12
|
-
"@hubspot/serverless-dev-runtime": "4.1
|
|
13
|
-
"@hubspot/ui-extensions-dev-server": "^0.
|
|
11
|
+
"@hubspot/cli-lib": "^4.2.1",
|
|
12
|
+
"@hubspot/serverless-dev-runtime": "4.2.1-beta.2",
|
|
13
|
+
"@hubspot/ui-extensions-dev-server": "^0.5.0",
|
|
14
14
|
"archiver": "^5.3.0",
|
|
15
15
|
"body-parser": "^1.19.0",
|
|
16
16
|
"chalk": "^4.1.2",
|
|
@@ -45,5 +45,5 @@
|
|
|
45
45
|
"publishConfig": {
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "9a111f2df1b19153efe867f3501599bfa4aedabe"
|
|
49
49
|
}
|