@hubspot/cli 5.2.0 → 5.2.1-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/bin/cli.js +6 -1
- package/commands/accounts/clean.js +3 -3
- package/commands/accounts/list.js +17 -5
- package/commands/project/dev.js +92 -260
- package/commands/project/upload.js +4 -1
- package/commands/sandbox/sync.js +5 -3
- package/lang/en.lyaml +51 -15
- package/lib/LocalDevManager.js +31 -33
- package/lib/accountTypes.js +34 -0
- package/lib/developerTestAccountCreate.js +186 -0
- package/lib/developerTestAccounts.js +50 -4
- package/lib/errorHandlers/apiErrors.js +6 -221
- package/lib/errorHandlers/fileSystemErrors.js +5 -40
- package/lib/errorHandlers/standardErrors.js +3 -9
- package/lib/localDev.js +401 -0
- package/lib/projectStructure.js +7 -0
- package/lib/projects.js +40 -2
- package/lib/prompts/developerTestAccountNamePrompt.js +29 -0
- package/lib/prompts/projectDevTargetAccountPrompt.js +84 -13
- package/lib/prompts/sandboxesPrompt.js +1 -1
- package/lib/sandboxSync.js +1 -1
- package/lib/sandboxes.js +1 -16
- package/lib/ui/index.js +10 -2
- package/package.json +5 -5
package/lib/localDev.js
ADDED
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
const { logger } = require('@hubspot/local-dev-lib/logger');
|
|
2
|
+
const {
|
|
3
|
+
HUBSPOT_ACCOUNT_TYPES,
|
|
4
|
+
HUBSPOT_ACCOUNT_TYPE_STRINGS,
|
|
5
|
+
} = require('@hubspot/local-dev-lib/constants/config');
|
|
6
|
+
const {
|
|
7
|
+
isMissingScopeError,
|
|
8
|
+
isSpecifiedError,
|
|
9
|
+
} = require('@hubspot/local-dev-lib/errors/apiErrors');
|
|
10
|
+
const { getHubSpotWebsiteOrigin } = require('@hubspot/local-dev-lib/urls');
|
|
11
|
+
const { getAccountConfig } = require('@hubspot/local-dev-lib/config');
|
|
12
|
+
const { createProject } = require('@hubspot/local-dev-lib/api/projects');
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
confirmDefaultAccountPrompt,
|
|
16
|
+
selectSandboxTargetAccountPrompt,
|
|
17
|
+
selectDeveloperTestTargetAccountPrompt,
|
|
18
|
+
} = require('./prompts/projectDevTargetAccountPrompt');
|
|
19
|
+
const { sandboxNamePrompt } = require('./prompts/sandboxesPrompt');
|
|
20
|
+
const {
|
|
21
|
+
developerTestAccountNamePrompt,
|
|
22
|
+
} = require('./prompts/developerTestAccountNamePrompt');
|
|
23
|
+
const { confirmPrompt } = require('./prompts/promptUtils');
|
|
24
|
+
const {
|
|
25
|
+
validateSandboxUsageLimits,
|
|
26
|
+
getSandboxTypeAsString,
|
|
27
|
+
getAvailableSyncTypes,
|
|
28
|
+
} = require('./sandboxes');
|
|
29
|
+
const { buildSandbox } = require('./sandboxCreate');
|
|
30
|
+
const { syncSandbox } = require('./sandboxSync');
|
|
31
|
+
const {
|
|
32
|
+
validateDevTestAccountUsageLimits,
|
|
33
|
+
} = require('./developerTestAccounts');
|
|
34
|
+
const { buildDeveloperTestAccount } = require('./developerTestAccountCreate');
|
|
35
|
+
const { logErrorInstance } = require('./errorHandlers/standardErrors');
|
|
36
|
+
const { uiCommandReference, uiLine, uiAccountDescription } = require('./ui');
|
|
37
|
+
const SpinniesManager = require('./ui/SpinniesManager');
|
|
38
|
+
const { i18n } = require('./lang');
|
|
39
|
+
const { EXIT_CODES } = require('./enums/exitCodes');
|
|
40
|
+
const { trackCommandMetadataUsage } = require('./usageTracking');
|
|
41
|
+
const {
|
|
42
|
+
isAppDeveloperAccount,
|
|
43
|
+
isDeveloperTestAccount,
|
|
44
|
+
} = require('./accountTypes');
|
|
45
|
+
const {
|
|
46
|
+
handleProjectUpload,
|
|
47
|
+
pollProjectBuildAndDeploy,
|
|
48
|
+
} = require('./projects');
|
|
49
|
+
const {
|
|
50
|
+
PROJECT_ERROR_TYPES,
|
|
51
|
+
PROJECT_BUILD_TEXT,
|
|
52
|
+
PROJECT_DEPLOY_TEXT,
|
|
53
|
+
} = require('./constants');
|
|
54
|
+
const {
|
|
55
|
+
logApiErrorInstance,
|
|
56
|
+
ApiErrorContext,
|
|
57
|
+
} = require('./errorHandlers/apiErrors');
|
|
58
|
+
|
|
59
|
+
const i18nKey = 'cli.lib.localDev';
|
|
60
|
+
|
|
61
|
+
// If the user passed in the --account flag, confirm they want to use that account as
|
|
62
|
+
// their target account, otherwise exit
|
|
63
|
+
const confirmDefaultAccountIsTarget = async accountConfig => {
|
|
64
|
+
logger.log();
|
|
65
|
+
const useDefaultAccount = await confirmDefaultAccountPrompt(
|
|
66
|
+
accountConfig.name,
|
|
67
|
+
isDeveloperTestAccount(accountConfig)
|
|
68
|
+
? HUBSPOT_ACCOUNT_TYPE_STRINGS[HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST]
|
|
69
|
+
: `${getSandboxTypeAsString(accountConfig.accountType)} sandbox`
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
if (!useDefaultAccount) {
|
|
73
|
+
logger.log(
|
|
74
|
+
i18n(
|
|
75
|
+
`${i18nKey}.confirmDefaultAccountIsTarget.declineDefaultAccountExplanation`,
|
|
76
|
+
{
|
|
77
|
+
useCommand: uiCommandReference('hs accounts use'),
|
|
78
|
+
devCommand: uiCommandReference('hs project dev'),
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
);
|
|
82
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// Confirm the default account is a developer account if developing public apps
|
|
87
|
+
const checkIfAppDeveloperAccount = accountConfig => {
|
|
88
|
+
if (!isAppDeveloperAccount(accountConfig)) {
|
|
89
|
+
logger.error(
|
|
90
|
+
i18n(
|
|
91
|
+
`${i18nKey}.checkCorrectParentAccountType.standardAccountNotSupported`
|
|
92
|
+
)
|
|
93
|
+
);
|
|
94
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// If the user isn't using the recommended account type, prompt them to use or create one
|
|
99
|
+
const suggestRecommendedNestedAccount = async (
|
|
100
|
+
accounts,
|
|
101
|
+
accountConfig,
|
|
102
|
+
hasPublicApps
|
|
103
|
+
) => {
|
|
104
|
+
logger.log();
|
|
105
|
+
uiLine();
|
|
106
|
+
if (hasPublicApps) {
|
|
107
|
+
logger.warn(
|
|
108
|
+
i18n(
|
|
109
|
+
`${i18nKey}.suggestRecommendedNestedAccount.publicAppNonDeveloperTestAccountWarning`
|
|
110
|
+
)
|
|
111
|
+
);
|
|
112
|
+
} else if (isAppDeveloperAccount(accountConfig)) {
|
|
113
|
+
logger.warn(
|
|
114
|
+
i18n(
|
|
115
|
+
`${i18nKey}.suggestRecommendedNestedAccount.publicAppNonDeveloperTestAccountWarning`
|
|
116
|
+
)
|
|
117
|
+
);
|
|
118
|
+
} else {
|
|
119
|
+
logger.warn(
|
|
120
|
+
i18n(`${i18nKey}.suggestRecommendedNestedAccount.nonSandboxWarning`)
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
uiLine();
|
|
124
|
+
logger.log();
|
|
125
|
+
|
|
126
|
+
const targetAccountPrompt = isAppDeveloperAccount(accountConfig)
|
|
127
|
+
? selectDeveloperTestTargetAccountPrompt
|
|
128
|
+
: selectSandboxTargetAccountPrompt;
|
|
129
|
+
|
|
130
|
+
return targetAccountPrompt(accounts, accountConfig, hasPublicApps);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// Create a new sandbox and return its accountId
|
|
134
|
+
const createSandboxForLocalDev = async (accountId, accountConfig, env) => {
|
|
135
|
+
try {
|
|
136
|
+
await validateSandboxUsageLimits(
|
|
137
|
+
accountConfig,
|
|
138
|
+
HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
|
|
139
|
+
env
|
|
140
|
+
);
|
|
141
|
+
} catch (err) {
|
|
142
|
+
if (isMissingScopeError(err)) {
|
|
143
|
+
logger.error(
|
|
144
|
+
i18n('cli.lib.sandbox.create.failure.scopes.message', {
|
|
145
|
+
accountName: accountConfig.name || accountId,
|
|
146
|
+
})
|
|
147
|
+
);
|
|
148
|
+
const websiteOrigin = getHubSpotWebsiteOrigin(env);
|
|
149
|
+
const url = `${websiteOrigin}/personal-access-key/${accountId}`;
|
|
150
|
+
logger.info(
|
|
151
|
+
i18n('cli.lib.sandbox.create.failure.scopes.instructions', {
|
|
152
|
+
accountName: accountConfig.name || accountId,
|
|
153
|
+
url,
|
|
154
|
+
})
|
|
155
|
+
);
|
|
156
|
+
} else {
|
|
157
|
+
logErrorInstance(err);
|
|
158
|
+
}
|
|
159
|
+
process.exit(EXIT_CODES.ERROR);
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
const { name } = await sandboxNamePrompt(
|
|
163
|
+
HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
trackCommandMetadataUsage(
|
|
167
|
+
'sandbox-create',
|
|
168
|
+
{ step: 'project-dev' },
|
|
169
|
+
accountId
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
const { result } = await buildSandbox({
|
|
173
|
+
name,
|
|
174
|
+
type: HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
|
|
175
|
+
accountConfig,
|
|
176
|
+
env,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
const targetAccountId = result.sandbox.sandboxHubId;
|
|
180
|
+
|
|
181
|
+
const sandboxAccountConfig = getAccountConfig(result.sandbox.sandboxHubId);
|
|
182
|
+
const syncTasks = await getAvailableSyncTypes(
|
|
183
|
+
accountConfig,
|
|
184
|
+
sandboxAccountConfig
|
|
185
|
+
);
|
|
186
|
+
await syncSandbox({
|
|
187
|
+
accountConfig: sandboxAccountConfig,
|
|
188
|
+
parentAccountConfig: accountConfig,
|
|
189
|
+
env,
|
|
190
|
+
syncTasks,
|
|
191
|
+
allowEarlyTermination: false, // Don't let user terminate early in this flow
|
|
192
|
+
skipPolling: true, // Skip polling, sync will run and complete in the background
|
|
193
|
+
});
|
|
194
|
+
return targetAccountId;
|
|
195
|
+
} catch (err) {
|
|
196
|
+
logErrorInstance(err);
|
|
197
|
+
process.exit(EXIT_CODES.ERROR);
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// Create a developer test account and return its accountId
|
|
202
|
+
const createDeveloperTestAccountForLocalDev = async (
|
|
203
|
+
accountId,
|
|
204
|
+
accountConfig,
|
|
205
|
+
env
|
|
206
|
+
) => {
|
|
207
|
+
let currentPortalCount = 0;
|
|
208
|
+
let maxTestPortals = 10;
|
|
209
|
+
try {
|
|
210
|
+
const validateResult = await validateDevTestAccountUsageLimits(
|
|
211
|
+
accountConfig
|
|
212
|
+
);
|
|
213
|
+
if (validateResult) {
|
|
214
|
+
currentPortalCount = validateResult.results
|
|
215
|
+
? validateResult.results.length
|
|
216
|
+
: 0;
|
|
217
|
+
maxTestPortals = validateResult.maxTestPortals;
|
|
218
|
+
}
|
|
219
|
+
} catch (err) {
|
|
220
|
+
if (isMissingScopeError(err)) {
|
|
221
|
+
logger.error(
|
|
222
|
+
i18n('cli.lib.developerTestAccount.create.failure.scopes.message', {
|
|
223
|
+
accountName: accountConfig.name || accountId,
|
|
224
|
+
})
|
|
225
|
+
);
|
|
226
|
+
const websiteOrigin = getHubSpotWebsiteOrigin(env);
|
|
227
|
+
const url = `${websiteOrigin}/personal-access-key/${accountId}`;
|
|
228
|
+
logger.info(
|
|
229
|
+
i18n(
|
|
230
|
+
'cli.lib.developerTestAccount.create.failure.scopes.instructions',
|
|
231
|
+
{
|
|
232
|
+
accountName: accountConfig.name || accountId,
|
|
233
|
+
url,
|
|
234
|
+
}
|
|
235
|
+
)
|
|
236
|
+
);
|
|
237
|
+
} else {
|
|
238
|
+
logErrorInstance(err);
|
|
239
|
+
}
|
|
240
|
+
process.exit(EXIT_CODES.ERROR);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
const { name } = await developerTestAccountNamePrompt(currentPortalCount);
|
|
245
|
+
trackCommandMetadataUsage(
|
|
246
|
+
'developer-test-account-create',
|
|
247
|
+
{ step: 'project-dev' },
|
|
248
|
+
accountId
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
const { result } = await buildDeveloperTestAccount({
|
|
252
|
+
name,
|
|
253
|
+
accountConfig,
|
|
254
|
+
env,
|
|
255
|
+
maxTestPortals,
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
return result.id;
|
|
259
|
+
} catch (err) {
|
|
260
|
+
logErrorInstance(err);
|
|
261
|
+
process.exit(EXIT_CODES.ERROR);
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
// Prompt the user to create a new project if one doesn't exist on their target account
|
|
266
|
+
const createNewProjectForLocalDev = async (
|
|
267
|
+
projectConfig,
|
|
268
|
+
targetAccountId,
|
|
269
|
+
shouldCreateWithoutConfirmation
|
|
270
|
+
) => {
|
|
271
|
+
// Create the project without prompting if this is a newly created sandbox
|
|
272
|
+
let shouldCreateProject = shouldCreateWithoutConfirmation;
|
|
273
|
+
|
|
274
|
+
if (!shouldCreateProject) {
|
|
275
|
+
logger.log();
|
|
276
|
+
uiLine();
|
|
277
|
+
logger.warn(
|
|
278
|
+
i18n(
|
|
279
|
+
`${i18nKey}.createNewProjectForLocalDev.projectMustExistExplanation`,
|
|
280
|
+
{
|
|
281
|
+
accountIdentifier: uiAccountDescription(targetAccountId),
|
|
282
|
+
projectName: projectConfig.name,
|
|
283
|
+
}
|
|
284
|
+
)
|
|
285
|
+
);
|
|
286
|
+
uiLine();
|
|
287
|
+
|
|
288
|
+
shouldCreateProject = await confirmPrompt(
|
|
289
|
+
i18n(`${i18nKey}.createNewProjectForLocalDev.createProject`, {
|
|
290
|
+
accountIdentifier: uiAccountDescription(targetAccountId),
|
|
291
|
+
projectName: projectConfig.name,
|
|
292
|
+
})
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (shouldCreateProject) {
|
|
297
|
+
SpinniesManager.add('createProject', {
|
|
298
|
+
text: i18n(`${i18nKey}.createNewProjectForLocalDev.creatingProject`, {
|
|
299
|
+
accountIdentifier: uiAccountDescription(targetAccountId),
|
|
300
|
+
projectName: projectConfig.name,
|
|
301
|
+
}),
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
try {
|
|
305
|
+
await createProject(targetAccountId, projectConfig.name);
|
|
306
|
+
SpinniesManager.succeed('createProject', {
|
|
307
|
+
text: i18n(`${i18nKey}.createNewProjectForLocalDev.createdProject`, {
|
|
308
|
+
accountIdentifier: uiAccountDescription(targetAccountId),
|
|
309
|
+
projectName: projectConfig.name,
|
|
310
|
+
}),
|
|
311
|
+
succeedColor: 'white',
|
|
312
|
+
});
|
|
313
|
+
} catch (err) {
|
|
314
|
+
SpinniesManager.fail('createProject');
|
|
315
|
+
logger.log(
|
|
316
|
+
i18n(`${i18nKey}.createNewProjectForLocalDev.failedToCreateProject`)
|
|
317
|
+
);
|
|
318
|
+
process.exit(EXIT_CODES.ERROR);
|
|
319
|
+
}
|
|
320
|
+
} else {
|
|
321
|
+
// We cannot continue if the project does not exist in the target account
|
|
322
|
+
logger.log();
|
|
323
|
+
logger.log(
|
|
324
|
+
i18n(`${i18nKey}.createNewProjectForLocalDev.choseNotToCreateProject`)
|
|
325
|
+
);
|
|
326
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
// Create an initial build if the project was newly created in the account
|
|
331
|
+
// Return the newly deployed build
|
|
332
|
+
const createInitialBuildForNewProject = async (
|
|
333
|
+
projectConfig,
|
|
334
|
+
projectDir,
|
|
335
|
+
targetAccountId
|
|
336
|
+
) => {
|
|
337
|
+
const initialUploadResult = await handleProjectUpload(
|
|
338
|
+
targetAccountId,
|
|
339
|
+
projectConfig,
|
|
340
|
+
projectDir,
|
|
341
|
+
(...args) => pollProjectBuildAndDeploy(...args, true),
|
|
342
|
+
i18n(`${i18nKey}.createInitialBuildForNewProject.initialUploadMessage`)
|
|
343
|
+
);
|
|
344
|
+
|
|
345
|
+
if (initialUploadResult.uploadError) {
|
|
346
|
+
if (
|
|
347
|
+
isSpecifiedError(initialUploadResult.uploadError, {
|
|
348
|
+
subCategory: PROJECT_ERROR_TYPES.PROJECT_LOCKED,
|
|
349
|
+
})
|
|
350
|
+
) {
|
|
351
|
+
logger.log();
|
|
352
|
+
logger.error(
|
|
353
|
+
i18n(`${i18nKey}.createInitialBuildForNewProject.projectLockedError`)
|
|
354
|
+
);
|
|
355
|
+
logger.log();
|
|
356
|
+
} else {
|
|
357
|
+
logApiErrorInstance(
|
|
358
|
+
initialUploadResult.uploadError,
|
|
359
|
+
new ApiErrorContext({
|
|
360
|
+
accountId: targetAccountId,
|
|
361
|
+
projectName: projectConfig.name,
|
|
362
|
+
})
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
process.exit(EXIT_CODES.ERROR);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (!initialUploadResult.succeeded) {
|
|
369
|
+
let subTasks = [];
|
|
370
|
+
|
|
371
|
+
if (initialUploadResult.buildResult.status === 'FAILURE') {
|
|
372
|
+
subTasks =
|
|
373
|
+
initialUploadResult.buildResult[PROJECT_BUILD_TEXT.SUBTASK_KEY];
|
|
374
|
+
} else if (initialUploadResult.deployResult.status === 'FAILURE') {
|
|
375
|
+
subTasks =
|
|
376
|
+
initialUploadResult.deployResult[PROJECT_DEPLOY_TEXT.SUBTASK_KEY];
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const failedSubTasks = subTasks.filter(task => task.status === 'FAILURE');
|
|
380
|
+
|
|
381
|
+
logger.log();
|
|
382
|
+
failedSubTasks.forEach(failedSubTask => {
|
|
383
|
+
console.error(failedSubTask.errorMessage);
|
|
384
|
+
});
|
|
385
|
+
logger.log();
|
|
386
|
+
|
|
387
|
+
process.exit(EXIT_CODES.ERROR);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return initialUploadResult.buildResult;
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
module.exports = {
|
|
394
|
+
confirmDefaultAccountIsTarget,
|
|
395
|
+
checkIfAppDeveloperAccount,
|
|
396
|
+
suggestRecommendedNestedAccount,
|
|
397
|
+
createSandboxForLocalDev,
|
|
398
|
+
createDeveloperTestAccountForLocalDev,
|
|
399
|
+
createNewProjectForLocalDev,
|
|
400
|
+
createInitialBuildForNewProject,
|
|
401
|
+
};
|
package/lib/projectStructure.js
CHANGED
|
@@ -118,9 +118,16 @@ async function findProjectComponents(projectSourceDir) {
|
|
|
118
118
|
return components;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
function getProjectComponentTypes(components) {
|
|
122
|
+
const projectContents = {};
|
|
123
|
+
components.forEach(({ type }) => (projectContents[type] = true));
|
|
124
|
+
return projectContents;
|
|
125
|
+
}
|
|
126
|
+
|
|
121
127
|
module.exports = {
|
|
122
128
|
CONFIG_FILES,
|
|
123
129
|
COMPONENT_TYPES,
|
|
124
130
|
findProjectComponents,
|
|
125
131
|
getAppCardConfigs,
|
|
132
|
+
getProjectComponentTypes,
|
|
126
133
|
};
|
package/lib/projects.js
CHANGED
|
@@ -26,8 +26,13 @@ const {
|
|
|
26
26
|
getDeployStructure,
|
|
27
27
|
fetchProject,
|
|
28
28
|
uploadProject,
|
|
29
|
+
fetchBuildWarnLogs,
|
|
30
|
+
fetchDeployWarnLogs,
|
|
29
31
|
} = require('@hubspot/local-dev-lib/api/projects');
|
|
30
|
-
const {
|
|
32
|
+
const {
|
|
33
|
+
isSpecifiedError,
|
|
34
|
+
isSpecifiedHubSpotAuthError,
|
|
35
|
+
} = require('@hubspot/local-dev-lib/errors/apiErrors');
|
|
31
36
|
const { shouldIgnoreFile } = require('@hubspot/local-dev-lib/ignoreRules');
|
|
32
37
|
const { getCwd, getAbsoluteFilePath } = require('@hubspot/local-dev-lib/path');
|
|
33
38
|
const { downloadGithubRepoContents } = require('@hubspot/local-dev-lib/github');
|
|
@@ -39,7 +44,6 @@ const SpinniesManager = require('./ui/SpinniesManager');
|
|
|
39
44
|
const {
|
|
40
45
|
logApiErrorInstance,
|
|
41
46
|
ApiErrorContext,
|
|
42
|
-
isSpecifiedHubSpotAuthError,
|
|
43
47
|
} = require('./errorHandlers/apiErrors');
|
|
44
48
|
const { HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH } = require('./constants');
|
|
45
49
|
|
|
@@ -443,7 +447,10 @@ const pollProjectBuildAndDeploy = async (
|
|
|
443
447
|
}
|
|
444
448
|
)
|
|
445
449
|
);
|
|
450
|
+
|
|
451
|
+
displayWarnLogs(accountId, projectConfig.name, buildId);
|
|
446
452
|
}
|
|
453
|
+
|
|
447
454
|
const deployStatus = await pollDeployStatus(
|
|
448
455
|
accountId,
|
|
449
456
|
projectConfig.name,
|
|
@@ -471,6 +478,14 @@ const pollProjectBuildAndDeploy = async (
|
|
|
471
478
|
logger.error(e);
|
|
472
479
|
}
|
|
473
480
|
|
|
481
|
+
if (result && result.deployResult) {
|
|
482
|
+
displayWarnLogs(
|
|
483
|
+
accountId,
|
|
484
|
+
projectConfig.name,
|
|
485
|
+
result.deployResult.deployId,
|
|
486
|
+
true
|
|
487
|
+
);
|
|
488
|
+
}
|
|
474
489
|
return result;
|
|
475
490
|
};
|
|
476
491
|
|
|
@@ -869,6 +884,28 @@ const createProjectComponent = async (
|
|
|
869
884
|
);
|
|
870
885
|
};
|
|
871
886
|
|
|
887
|
+
const displayWarnLogs = async (
|
|
888
|
+
accountId,
|
|
889
|
+
projectName,
|
|
890
|
+
taskId,
|
|
891
|
+
isDeploy = false
|
|
892
|
+
) => {
|
|
893
|
+
let result;
|
|
894
|
+
|
|
895
|
+
if (isDeploy) {
|
|
896
|
+
result = await fetchDeployWarnLogs(accountId, projectName, taskId);
|
|
897
|
+
} else {
|
|
898
|
+
result = await fetchBuildWarnLogs(accountId, projectName, taskId);
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
if (result && result.logs.length) {
|
|
902
|
+
result.logs.forEach(log => {
|
|
903
|
+
logger.warn(log.message);
|
|
904
|
+
logger.log('');
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
};
|
|
908
|
+
|
|
872
909
|
module.exports = {
|
|
873
910
|
writeProjectConfig,
|
|
874
911
|
getProjectConfig,
|
|
@@ -885,4 +922,5 @@ module.exports = {
|
|
|
885
922
|
ensureProjectExists,
|
|
886
923
|
logFeedbackMessage,
|
|
887
924
|
createProjectComponent,
|
|
925
|
+
displayWarnLogs,
|
|
888
926
|
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const { promptUser } = require('./promptUtils');
|
|
2
|
+
const { i18n } = require('../lang');
|
|
3
|
+
const { accountNameExistsInConfig } = require('@hubspot/local-dev-lib/config');
|
|
4
|
+
|
|
5
|
+
const i18nKey = 'cli.lib.prompts.developerTestAccountPrompt';
|
|
6
|
+
|
|
7
|
+
const developerTestAccountNamePrompt = currentPortalCount => {
|
|
8
|
+
return promptUser([
|
|
9
|
+
{
|
|
10
|
+
name: 'name',
|
|
11
|
+
message: i18n(`${i18nKey}.name.message`),
|
|
12
|
+
validate(val) {
|
|
13
|
+
if (typeof val !== 'string') {
|
|
14
|
+
return i18n(`${i18nKey}.name.errors.invalidName`);
|
|
15
|
+
} else if (!val.length) {
|
|
16
|
+
return i18n(`${i18nKey}.name.errors.nameRequired`);
|
|
17
|
+
}
|
|
18
|
+
return accountNameExistsInConfig(val)
|
|
19
|
+
? i18n(`${i18nKey}.name.errors.accountNameExists`, { name: val })
|
|
20
|
+
: true;
|
|
21
|
+
},
|
|
22
|
+
default: `Developer test account ${currentPortalCount + 1}`,
|
|
23
|
+
},
|
|
24
|
+
]);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
module.exports = {
|
|
28
|
+
developerTestAccountNamePrompt,
|
|
29
|
+
};
|
|
@@ -1,28 +1,36 @@
|
|
|
1
1
|
const { promptUser } = require('./promptUtils');
|
|
2
2
|
const { i18n } = require('../lang');
|
|
3
3
|
const { uiAccountDescription, uiCommandReference } = require('../ui');
|
|
4
|
-
const { isSandbox } = require('../
|
|
4
|
+
const { isSandbox, isDeveloperTestAccount } = require('../accountTypes');
|
|
5
5
|
const { getAccountId } = require('@hubspot/local-dev-lib/config');
|
|
6
6
|
const { getSandboxUsageLimits } = require('@hubspot/local-dev-lib/sandboxes');
|
|
7
7
|
const {
|
|
8
8
|
HUBSPOT_ACCOUNT_TYPES,
|
|
9
|
+
HUBSPOT_ACCOUNT_TYPE_STRINGS,
|
|
9
10
|
} = require('@hubspot/local-dev-lib/constants/config');
|
|
10
11
|
const { logger } = require('@hubspot/local-dev-lib/logger');
|
|
12
|
+
const {
|
|
13
|
+
fetchDeveloperTestAccounts,
|
|
14
|
+
} = require('@hubspot/local-dev-lib/developerTestAccounts');
|
|
11
15
|
|
|
12
16
|
const i18nKey = 'cli.lib.prompts.projectDevTargetAccountPrompt';
|
|
13
17
|
|
|
14
|
-
const
|
|
18
|
+
const mapNestedAccount = accountConfig => ({
|
|
15
19
|
name: uiAccountDescription(accountConfig.portalId, false),
|
|
16
20
|
value: {
|
|
17
21
|
targetAccountId: getAccountId(accountConfig.name),
|
|
18
|
-
|
|
22
|
+
createNestedAccount: false,
|
|
23
|
+
parentAccountId: accountConfig.parentAccountId,
|
|
19
24
|
},
|
|
20
25
|
});
|
|
21
26
|
|
|
22
|
-
const
|
|
23
|
-
|
|
27
|
+
const selectSandboxTargetAccountPrompt = async (
|
|
28
|
+
accounts,
|
|
29
|
+
defaultAccountConfig
|
|
30
|
+
) => {
|
|
24
31
|
const defaultAccountId = getAccountId(defaultAccountConfig.name);
|
|
25
|
-
|
|
32
|
+
let choices = [];
|
|
33
|
+
let sandboxUsage = {};
|
|
26
34
|
try {
|
|
27
35
|
sandboxUsage = await getSandboxUsageLimits(defaultAccountId);
|
|
28
36
|
} catch (err) {
|
|
@@ -48,20 +56,19 @@ const selectTargetAccountPrompt = async (accounts, defaultAccountConfig) => {
|
|
|
48
56
|
});
|
|
49
57
|
}
|
|
50
58
|
}
|
|
51
|
-
|
|
52
59
|
// Order choices by Developer Sandbox -> Standard Sandbox
|
|
53
|
-
|
|
60
|
+
choices = [
|
|
54
61
|
...sandboxAccounts
|
|
55
62
|
.filter(a => a.accountType === HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX)
|
|
56
|
-
.map(
|
|
63
|
+
.map(mapNestedAccount),
|
|
57
64
|
...sandboxAccounts
|
|
58
65
|
.filter(a => a.accountType === HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX)
|
|
59
|
-
.map(
|
|
66
|
+
.map(mapNestedAccount),
|
|
60
67
|
{
|
|
61
68
|
name: i18n(`${i18nKey}.createNewSandboxOption`),
|
|
62
69
|
value: {
|
|
63
70
|
targetAccountId: null,
|
|
64
|
-
|
|
71
|
+
createNestedAccount: true,
|
|
65
72
|
},
|
|
66
73
|
disabled: disabledMessage,
|
|
67
74
|
},
|
|
@@ -69,17 +76,80 @@ const selectTargetAccountPrompt = async (accounts, defaultAccountConfig) => {
|
|
|
69
76
|
name: i18n(`${i18nKey}.chooseDefaultAccountOption`),
|
|
70
77
|
value: {
|
|
71
78
|
targetAccountId: defaultAccountId,
|
|
72
|
-
|
|
79
|
+
createNestedAccount: false,
|
|
73
80
|
},
|
|
74
81
|
},
|
|
75
82
|
];
|
|
76
83
|
|
|
84
|
+
return selectTargetAccountPrompt(
|
|
85
|
+
defaultAccountId,
|
|
86
|
+
'sandbox account',
|
|
87
|
+
choices
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const selectDeveloperTestTargetAccountPrompt = async (
|
|
92
|
+
accounts,
|
|
93
|
+
defaultAccountConfig
|
|
94
|
+
) => {
|
|
95
|
+
const defaultAccountId = getAccountId(defaultAccountConfig.name);
|
|
96
|
+
let choices = [];
|
|
97
|
+
let devTestAccountUsage = undefined;
|
|
98
|
+
try {
|
|
99
|
+
devTestAccountUsage = await fetchDeveloperTestAccounts(defaultAccountId);
|
|
100
|
+
} catch (err) {
|
|
101
|
+
logger.debug('Unable to fetch developer test account usage limits: ', err);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const devTestAccounts = accounts
|
|
105
|
+
.reverse()
|
|
106
|
+
.filter(
|
|
107
|
+
config =>
|
|
108
|
+
isDeveloperTestAccount(config) &&
|
|
109
|
+
config.parentAccountId === defaultAccountId
|
|
110
|
+
);
|
|
111
|
+
let disabledMessage = false;
|
|
112
|
+
if (
|
|
113
|
+
devTestAccountUsage &&
|
|
114
|
+
devTestAccountUsage.results.length >= devTestAccountUsage.maxTestPortals
|
|
115
|
+
) {
|
|
116
|
+
disabledMessage = i18n(`${i18nKey}.developerTestAccountLimit`, {
|
|
117
|
+
authCommand: uiCommandReference('hs auth'),
|
|
118
|
+
limit: devTestAccountUsage.maxTestPortals,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
choices = [
|
|
123
|
+
...devTestAccounts.map(mapNestedAccount),
|
|
124
|
+
{
|
|
125
|
+
name: i18n(`${i18nKey}.createNewDeveloperTestAccountOption`),
|
|
126
|
+
value: {
|
|
127
|
+
targetAccountId: null,
|
|
128
|
+
createNestedAccount: true,
|
|
129
|
+
},
|
|
130
|
+
disabled: disabledMessage,
|
|
131
|
+
},
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
return selectTargetAccountPrompt(
|
|
135
|
+
defaultAccountId,
|
|
136
|
+
HUBSPOT_ACCOUNT_TYPE_STRINGS[HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST],
|
|
137
|
+
choices
|
|
138
|
+
);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const selectTargetAccountPrompt = async (
|
|
142
|
+
defaultAccountId,
|
|
143
|
+
accountType,
|
|
144
|
+
choices
|
|
145
|
+
) => {
|
|
77
146
|
const { targetAccountInfo } = await promptUser([
|
|
78
147
|
{
|
|
79
148
|
name: 'targetAccountInfo',
|
|
80
149
|
type: 'list',
|
|
81
150
|
message: i18n(`${i18nKey}.promptMessage`, {
|
|
82
151
|
accountIdentifier: uiAccountDescription(defaultAccountId),
|
|
152
|
+
accountType,
|
|
83
153
|
}),
|
|
84
154
|
choices,
|
|
85
155
|
},
|
|
@@ -103,6 +173,7 @@ const confirmDefaultAccountPrompt = async (accountName, accountType) => {
|
|
|
103
173
|
};
|
|
104
174
|
|
|
105
175
|
module.exports = {
|
|
106
|
-
|
|
176
|
+
selectSandboxTargetAccountPrompt,
|
|
177
|
+
selectDeveloperTestTargetAccountPrompt,
|
|
107
178
|
confirmDefaultAccountPrompt,
|
|
108
179
|
};
|
|
@@ -5,7 +5,7 @@ const { uiAccountDescription } = require('../ui');
|
|
|
5
5
|
const {
|
|
6
6
|
HUBSPOT_ACCOUNT_TYPES,
|
|
7
7
|
} = require('@hubspot/local-dev-lib/constants/config');
|
|
8
|
-
const { isSandbox } = require('../
|
|
8
|
+
const { isSandbox } = require('../accountTypes');
|
|
9
9
|
|
|
10
10
|
const i18nKey = 'cli.lib.prompts.sandboxesPrompt';
|
|
11
11
|
|
package/lib/sandboxSync.js
CHANGED
|
@@ -2,11 +2,11 @@ const SpinniesManager = require('./ui/SpinniesManager');
|
|
|
2
2
|
const { getHubSpotWebsiteOrigin } = require('@hubspot/local-dev-lib/urls');
|
|
3
3
|
const { logger } = require('@hubspot/local-dev-lib/logger');
|
|
4
4
|
const { i18n } = require('./lang');
|
|
5
|
+
const { isDevelopmentSandbox } = require('./accountTypes');
|
|
5
6
|
const {
|
|
6
7
|
getAvailableSyncTypes,
|
|
7
8
|
pollSyncTaskStatus,
|
|
8
9
|
syncTypes,
|
|
9
|
-
isDevelopmentSandbox,
|
|
10
10
|
} = require('./sandboxes');
|
|
11
11
|
const { initiateSync } = require('@hubspot/local-dev-lib/sandboxes');
|
|
12
12
|
const {
|