@hubspot/cli 5.2.1-beta.0 → 5.2.1-beta.10
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 +7 -2
- package/bin/hs +1 -1
- package/commands/accounts/clean.js +8 -8
- package/commands/accounts/info.js +3 -3
- package/commands/accounts/list.js +14 -13
- package/commands/accounts/remove.js +1 -1
- package/commands/accounts/rename.js +3 -3
- package/commands/accounts/use.js +1 -1
- package/commands/accounts.js +3 -3
- package/commands/auth.js +7 -9
- package/commands/cms/convertFields.js +1 -1
- package/commands/cms/lighthouseScore.js +4 -4
- package/commands/cms/reactModules.js +1 -1
- package/commands/cms.js +3 -3
- package/commands/config/set/allowUsageTracking.js +1 -2
- package/commands/config/set/defaultMode.js +1 -1
- package/commands/config/set/httpTimeout.js +1 -1
- package/commands/config/set.js +1 -1
- package/commands/config.js +3 -3
- package/commands/create/api-sample.js +1 -1
- package/commands/create/module.js +1 -1
- package/commands/create/template.js +1 -1
- package/commands/create.js +1 -1
- package/commands/customObject/create.js +1 -1
- package/commands/customObject/schema/create.js +2 -3
- package/commands/customObject/schema/delete.js +1 -2
- package/commands/customObject/schema/fetch-all.js +1 -2
- package/commands/customObject/schema/fetch.js +1 -2
- package/commands/customObject/schema/list.js +1 -1
- package/commands/customObject/schema/update.js +2 -3
- package/commands/customObject/schema.js +1 -1
- package/commands/customObject.js +3 -3
- package/commands/feedback.js +4 -6
- package/commands/fetch.js +6 -6
- package/commands/filemanager/fetch.js +4 -4
- package/commands/filemanager/upload.js +4 -4
- package/commands/filemanager.js +4 -4
- package/commands/functions/deploy.js +7 -23
- package/commands/functions/list.js +4 -4
- package/commands/functions/server.js +4 -4
- package/commands/functions.js +3 -3
- package/commands/hubdb/clear.js +4 -4
- package/commands/hubdb/create.js +4 -4
- package/commands/hubdb/delete.js +4 -4
- package/commands/hubdb/fetch.js +4 -4
- package/commands/hubdb.js +3 -3
- package/commands/init.js +6 -8
- package/commands/lint.js +3 -3
- package/commands/list.js +4 -4
- package/commands/logs.js +4 -4
- package/commands/module/marketplace-validate.js +5 -5
- package/commands/module.js +3 -3
- package/commands/mv.js +4 -4
- package/commands/open.js +4 -4
- package/commands/project/add.js +1 -1
- package/commands/project/create.js +4 -4
- package/commands/project/deploy.js +4 -4
- package/commands/project/dev.js +139 -264
- package/commands/project/download.js +11 -7
- package/commands/project/listBuilds.js +4 -4
- package/commands/project/logs.js +4 -4
- package/commands/project/migrateApp.js +227 -0
- package/commands/project/open.js +12 -8
- package/commands/project/upload.js +15 -7
- package/commands/project/watch.js +4 -4
- package/commands/project.js +5 -3
- package/commands/remove.js +4 -4
- package/commands/sandbox/create.js +16 -16
- package/commands/sandbox/delete.js +5 -5
- package/commands/sandbox/sync.js +11 -9
- package/commands/sandbox.js +3 -3
- package/commands/secrets/addSecret.js +4 -4
- package/commands/secrets/deleteSecret.js +4 -4
- package/commands/secrets/listSecrets.js +4 -4
- package/commands/secrets/updateSecret.js +4 -4
- package/commands/secrets.js +3 -3
- package/commands/theme/generate-selectors.js +1 -1
- package/commands/theme/marketplace-validate.js +5 -5
- package/commands/theme/preview.js +52 -17
- package/commands/theme.js +1 -1
- package/commands/upload.js +5 -5
- package/commands/watch.js +61 -18
- package/jest.config.js +1 -0
- package/lang/en.lyaml +1426 -1336
- package/lib/DevServerManager.js +3 -2
- package/lib/LocalDevManager.js +194 -38
- package/lib/__tests__/{commonOpts.js → commonOpts.test.js} +3 -0
- package/lib/__tests__/downloadProjectPrompt.test.js +31 -0
- package/lib/__tests__/projects.test.js +13 -17
- package/lib/__tests__/{serverlessLogs.js → serverlessLogs.test.js} +1 -0
- package/lib/accountTypes.js +34 -0
- package/lib/buildAccount.js +197 -0
- package/lib/commonOpts.js +1 -1
- package/lib/constants.js +10 -0
- package/lib/developerTestAccounts.js +98 -4
- package/lib/errorHandlers/apiErrors.js +1 -1
- package/lib/errorHandlers/overrideErrors.js +1 -1
- package/lib/errorHandlers/standardErrors.js +1 -1
- package/lib/generate-selectors.js +1 -1
- package/lib/localDev.js +451 -0
- package/lib/marketplace-validate.js +11 -3
- package/lib/polling.js +26 -0
- package/lib/process.js +1 -1
- package/lib/projectStructure.js +12 -2
- package/lib/projects.js +99 -10
- package/lib/projectsWatch.js +1 -1
- package/lib/prompts/accountNamePrompt.js +81 -0
- package/lib/prompts/accountsPrompt.js +1 -1
- package/lib/prompts/activeInstallConfirmationPrompt.js +20 -0
- package/lib/prompts/buildIdPrompt.js +1 -1
- package/lib/prompts/cleanUploadPrompt.js +1 -1
- package/lib/prompts/cmsFieldPrompt.js +1 -1
- package/lib/prompts/createApiSamplePrompt.js +1 -1
- package/lib/prompts/createFunctionPrompt.js +1 -1
- package/lib/prompts/createModulePrompt.js +1 -1
- package/lib/prompts/createProjectPrompt.js +32 -10
- package/lib/prompts/createTemplatePrompt.js +1 -1
- package/lib/prompts/downloadProjectPrompt.js +5 -6
- package/lib/prompts/feedbackPrompt.js +1 -1
- package/lib/prompts/folderOverwritePrompt.js +1 -1
- package/lib/prompts/installPublicAppPrompt.js +42 -0
- package/lib/prompts/personalAccessKeyPrompt.js +3 -3
- package/lib/prompts/previewPrompt.js +19 -1
- package/lib/prompts/projectAddPrompt.js +1 -1
- package/lib/prompts/projectDevTargetAccountPrompt.js +127 -14
- package/lib/prompts/projectNamePrompt.js +2 -2
- package/lib/prompts/projectsLogsPrompt.js +1 -1
- package/lib/prompts/sandboxesPrompt.js +14 -43
- package/lib/prompts/secretPrompt.js +1 -1
- package/lib/prompts/selectPublicAppPrompt.js +69 -0
- package/lib/prompts/setAsDefaultAccountPrompt.js +1 -1
- package/lib/prompts/uploadPrompt.js +1 -1
- package/lib/sandboxSync.js +2 -2
- package/lib/sandboxes.js +168 -30
- package/lib/ui/git.js +1 -1
- package/lib/ui/index.js +5 -14
- package/lib/ui/serverlessFunctionLogs.js +1 -1
- package/package.json +6 -6
- package/lib/prompts/enterAccountNamePrompt.js +0 -33
- package/lib/sandboxCreate.js +0 -319
- /package/lib/__tests__/{validation.js → validation.test.js} +0 -0
package/lib/localDev.js
ADDED
|
@@ -0,0 +1,451 @@
|
|
|
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, getEnv } = require('@hubspot/local-dev-lib/config');
|
|
12
|
+
const { createProject } = require('@hubspot/local-dev-lib/api/projects');
|
|
13
|
+
const {
|
|
14
|
+
ENVIRONMENTS,
|
|
15
|
+
} = require('@hubspot/local-dev-lib/constants/environments');
|
|
16
|
+
const {
|
|
17
|
+
confirmDefaultAccountPrompt,
|
|
18
|
+
selectSandboxTargetAccountPrompt,
|
|
19
|
+
selectDeveloperTestTargetAccountPrompt,
|
|
20
|
+
confirmUseExistingDeveloperTestAccountPrompt,
|
|
21
|
+
} = require('./prompts/projectDevTargetAccountPrompt');
|
|
22
|
+
const { confirmPrompt } = require('./prompts/promptUtils');
|
|
23
|
+
const {
|
|
24
|
+
validateSandboxUsageLimits,
|
|
25
|
+
getAvailableSyncTypes,
|
|
26
|
+
} = require('./sandboxes');
|
|
27
|
+
const { syncSandbox } = require('./sandboxSync');
|
|
28
|
+
const {
|
|
29
|
+
validateDevTestAccountUsageLimits,
|
|
30
|
+
} = require('./developerTestAccounts');
|
|
31
|
+
const { logErrorInstance } = require('./errorHandlers/standardErrors');
|
|
32
|
+
const { uiCommandReference, uiLine, uiAccountDescription } = require('./ui');
|
|
33
|
+
const SpinniesManager = require('./ui/SpinniesManager');
|
|
34
|
+
const { i18n } = require('./lang');
|
|
35
|
+
const { EXIT_CODES } = require('./enums/exitCodes');
|
|
36
|
+
const { trackCommandMetadataUsage } = require('./usageTracking');
|
|
37
|
+
const {
|
|
38
|
+
isAppDeveloperAccount,
|
|
39
|
+
isDeveloperTestAccount,
|
|
40
|
+
} = require('./accountTypes');
|
|
41
|
+
const {
|
|
42
|
+
handleProjectUpload,
|
|
43
|
+
pollProjectBuildAndDeploy,
|
|
44
|
+
} = require('./projects');
|
|
45
|
+
const {
|
|
46
|
+
PROJECT_ERROR_TYPES,
|
|
47
|
+
PROJECT_BUILD_TEXT,
|
|
48
|
+
PROJECT_DEPLOY_TEXT,
|
|
49
|
+
} = require('./constants');
|
|
50
|
+
const {
|
|
51
|
+
logApiErrorInstance,
|
|
52
|
+
ApiErrorContext,
|
|
53
|
+
} = require('./errorHandlers/apiErrors');
|
|
54
|
+
const {
|
|
55
|
+
PERSONAL_ACCESS_KEY_AUTH_METHOD,
|
|
56
|
+
} = require('@hubspot/local-dev-lib/constants/auth');
|
|
57
|
+
const { buildNewAccount, saveAccountToConfig } = require('./buildAccount');
|
|
58
|
+
const { hubspotAccountNamePrompt } = require('./prompts/accountNamePrompt');
|
|
59
|
+
|
|
60
|
+
const i18nKey = 'lib.localDev';
|
|
61
|
+
|
|
62
|
+
// If the user passed in the --account flag, confirm they want to use that account as
|
|
63
|
+
// their target account, otherwise exit
|
|
64
|
+
const confirmDefaultAccountIsTarget = async accountConfig => {
|
|
65
|
+
logger.log();
|
|
66
|
+
const useDefaultAccount = await confirmDefaultAccountPrompt(
|
|
67
|
+
accountConfig.name,
|
|
68
|
+
HUBSPOT_ACCOUNT_TYPE_STRINGS[accountConfig.accountType]
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
if (!useDefaultAccount) {
|
|
72
|
+
logger.log(
|
|
73
|
+
i18n(
|
|
74
|
+
`${i18nKey}.confirmDefaultAccountIsTarget.declineDefaultAccountExplanation`,
|
|
75
|
+
{
|
|
76
|
+
useCommand: uiCommandReference('hs accounts use'),
|
|
77
|
+
devCommand: uiCommandReference('hs project dev'),
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
);
|
|
81
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// Confirm the default account is a developer account if developing public apps
|
|
86
|
+
const checkIfAppDeveloperAccount = accountConfig => {
|
|
87
|
+
if (!isAppDeveloperAccount(accountConfig)) {
|
|
88
|
+
logger.error(i18n(`${i18nKey}.checkIfAppDevloperAccount`));
|
|
89
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Confirm the default account is a developer account if developing public apps
|
|
94
|
+
const checkIfDeveloperTestAccount = accountConfig => {
|
|
95
|
+
if (!isDeveloperTestAccount(accountConfig)) {
|
|
96
|
+
logger.error(i18n(`${i18nKey}.checkIfDeveloperTestAccount`));
|
|
97
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// If the user isn't using the recommended account type, prompt them to use or create one
|
|
102
|
+
const suggestRecommendedNestedAccount = async (
|
|
103
|
+
accounts,
|
|
104
|
+
accountConfig,
|
|
105
|
+
hasPublicApps
|
|
106
|
+
) => {
|
|
107
|
+
logger.log();
|
|
108
|
+
uiLine();
|
|
109
|
+
if (hasPublicApps) {
|
|
110
|
+
logger.log(
|
|
111
|
+
i18n(
|
|
112
|
+
`${i18nKey}.suggestRecommendedNestedAccount.publicAppNonDeveloperTestAccountWarning`
|
|
113
|
+
)
|
|
114
|
+
);
|
|
115
|
+
} else if (isAppDeveloperAccount(accountConfig)) {
|
|
116
|
+
logger.error(
|
|
117
|
+
i18n(
|
|
118
|
+
`${i18nKey}.suggestRecommendedNestedAccount.privateAppInAppDeveloperAccountError`
|
|
119
|
+
)
|
|
120
|
+
);
|
|
121
|
+
process.exit(EXIT_CODES.ERROR);
|
|
122
|
+
} else {
|
|
123
|
+
logger.log(
|
|
124
|
+
i18n(`${i18nKey}.suggestRecommendedNestedAccount.nonSandboxWarning`)
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
uiLine();
|
|
128
|
+
logger.log();
|
|
129
|
+
|
|
130
|
+
const targetAccountPrompt = isAppDeveloperAccount(accountConfig)
|
|
131
|
+
? selectDeveloperTestTargetAccountPrompt
|
|
132
|
+
: selectSandboxTargetAccountPrompt;
|
|
133
|
+
|
|
134
|
+
return targetAccountPrompt(accounts, accountConfig, hasPublicApps);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// Create a new sandbox and return its accountId
|
|
138
|
+
const createSandboxForLocalDev = async (accountId, accountConfig, env) => {
|
|
139
|
+
try {
|
|
140
|
+
await validateSandboxUsageLimits(
|
|
141
|
+
accountConfig,
|
|
142
|
+
HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
|
|
143
|
+
env
|
|
144
|
+
);
|
|
145
|
+
} catch (err) {
|
|
146
|
+
if (isMissingScopeError(err)) {
|
|
147
|
+
logger.error(
|
|
148
|
+
i18n('lib.sandbox.create.failure.scopes.message', {
|
|
149
|
+
accountName: accountConfig.name || accountId,
|
|
150
|
+
})
|
|
151
|
+
);
|
|
152
|
+
const websiteOrigin = getHubSpotWebsiteOrigin(env);
|
|
153
|
+
const url = `${websiteOrigin}/personal-access-key/${accountId}`;
|
|
154
|
+
logger.info(
|
|
155
|
+
i18n('lib.sandbox.create.failure.scopes.instructions', {
|
|
156
|
+
accountName: accountConfig.name || accountId,
|
|
157
|
+
url,
|
|
158
|
+
})
|
|
159
|
+
);
|
|
160
|
+
} else {
|
|
161
|
+
logErrorInstance(err);
|
|
162
|
+
}
|
|
163
|
+
process.exit(EXIT_CODES.ERROR);
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
const { name } = await hubspotAccountNamePrompt({
|
|
167
|
+
accountType: HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
trackCommandMetadataUsage(
|
|
171
|
+
'sandbox-create',
|
|
172
|
+
{ step: 'project-dev' },
|
|
173
|
+
accountId
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
const { result } = await buildNewAccount({
|
|
177
|
+
name,
|
|
178
|
+
accountType: HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
|
|
179
|
+
accountConfig,
|
|
180
|
+
env,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const targetAccountId = result.sandbox.sandboxHubId;
|
|
184
|
+
|
|
185
|
+
const sandboxAccountConfig = getAccountConfig(result.sandbox.sandboxHubId);
|
|
186
|
+
const syncTasks = await getAvailableSyncTypes(
|
|
187
|
+
accountConfig,
|
|
188
|
+
sandboxAccountConfig
|
|
189
|
+
);
|
|
190
|
+
await syncSandbox({
|
|
191
|
+
accountConfig: sandboxAccountConfig,
|
|
192
|
+
parentAccountConfig: accountConfig,
|
|
193
|
+
env,
|
|
194
|
+
syncTasks,
|
|
195
|
+
allowEarlyTermination: false, // Don't let user terminate early in this flow
|
|
196
|
+
skipPolling: true, // Skip polling, sync will run and complete in the background
|
|
197
|
+
});
|
|
198
|
+
return targetAccountId;
|
|
199
|
+
} catch (err) {
|
|
200
|
+
logErrorInstance(err);
|
|
201
|
+
process.exit(EXIT_CODES.ERROR);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// Create a developer test account and return its accountId
|
|
206
|
+
const createDeveloperTestAccountForLocalDev = async (
|
|
207
|
+
accountId,
|
|
208
|
+
accountConfig,
|
|
209
|
+
env
|
|
210
|
+
) => {
|
|
211
|
+
let currentPortalCount = 0;
|
|
212
|
+
let maxTestPortals = 10;
|
|
213
|
+
try {
|
|
214
|
+
const validateResult = await validateDevTestAccountUsageLimits(
|
|
215
|
+
accountConfig
|
|
216
|
+
);
|
|
217
|
+
if (validateResult) {
|
|
218
|
+
currentPortalCount = validateResult.results
|
|
219
|
+
? validateResult.results.length
|
|
220
|
+
: 0;
|
|
221
|
+
maxTestPortals = validateResult.maxTestPortals;
|
|
222
|
+
}
|
|
223
|
+
} catch (err) {
|
|
224
|
+
if (isMissingScopeError(err)) {
|
|
225
|
+
logger.error(
|
|
226
|
+
i18n('lib.developerTestAccount.create.failure.scopes.message', {
|
|
227
|
+
accountName: accountConfig.name || accountId,
|
|
228
|
+
})
|
|
229
|
+
);
|
|
230
|
+
const websiteOrigin = getHubSpotWebsiteOrigin(env);
|
|
231
|
+
const url = `${websiteOrigin}/personal-access-key/${accountId}`;
|
|
232
|
+
logger.info(
|
|
233
|
+
i18n('lib.developerTestAccount.create.failure.scopes.instructions', {
|
|
234
|
+
accountName: accountConfig.name || accountId,
|
|
235
|
+
url,
|
|
236
|
+
})
|
|
237
|
+
);
|
|
238
|
+
} else {
|
|
239
|
+
logErrorInstance(err);
|
|
240
|
+
}
|
|
241
|
+
process.exit(EXIT_CODES.ERROR);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
try {
|
|
245
|
+
const { name } = await hubspotAccountNamePrompt({
|
|
246
|
+
currentPortalCount,
|
|
247
|
+
accountType: HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST,
|
|
248
|
+
});
|
|
249
|
+
trackCommandMetadataUsage(
|
|
250
|
+
'developer-test-account-create',
|
|
251
|
+
{ step: 'project-dev' },
|
|
252
|
+
accountId
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
const { result } = await buildNewAccount({
|
|
256
|
+
name,
|
|
257
|
+
accountType: HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST,
|
|
258
|
+
accountConfig,
|
|
259
|
+
env,
|
|
260
|
+
portalLimit: maxTestPortals,
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
return result.id;
|
|
264
|
+
} catch (err) {
|
|
265
|
+
logErrorInstance(err);
|
|
266
|
+
process.exit(EXIT_CODES.ERROR);
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
// Prompt user to confirm usage of an existing developer test account that is not currently in the config
|
|
271
|
+
const useExistingDevTestAccount = async (env, account) => {
|
|
272
|
+
const useExistingDevTestAcct = await confirmUseExistingDeveloperTestAccountPrompt(
|
|
273
|
+
account
|
|
274
|
+
);
|
|
275
|
+
if (!useExistingDevTestAcct) {
|
|
276
|
+
logger.log('');
|
|
277
|
+
logger.log(
|
|
278
|
+
i18n(
|
|
279
|
+
`${i18nKey}.confirmDefaultAccountIsTarget.declineDefaultAccountExplanation`,
|
|
280
|
+
{
|
|
281
|
+
useCommand: uiCommandReference('hs accounts use'),
|
|
282
|
+
devCommand: uiCommandReference('hs project dev'),
|
|
283
|
+
}
|
|
284
|
+
)
|
|
285
|
+
);
|
|
286
|
+
logger.log('');
|
|
287
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
288
|
+
}
|
|
289
|
+
const devTestAcctConfigName = await saveAccountToConfig({
|
|
290
|
+
env,
|
|
291
|
+
accountName: account.accountName,
|
|
292
|
+
accountId: account.id,
|
|
293
|
+
});
|
|
294
|
+
logger.success(
|
|
295
|
+
i18n(`lib.developerTestAccount.create.success.configFileUpdated`, {
|
|
296
|
+
accountName: devTestAcctConfigName,
|
|
297
|
+
authType: PERSONAL_ACCESS_KEY_AUTH_METHOD.name,
|
|
298
|
+
})
|
|
299
|
+
);
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
// Prompt the user to create a new project if one doesn't exist on their target account
|
|
303
|
+
const createNewProjectForLocalDev = async (
|
|
304
|
+
projectConfig,
|
|
305
|
+
targetAccountId,
|
|
306
|
+
shouldCreateWithoutConfirmation,
|
|
307
|
+
hasPublicApps
|
|
308
|
+
) => {
|
|
309
|
+
// Create the project without prompting if this is a newly created sandbox
|
|
310
|
+
let shouldCreateProject = shouldCreateWithoutConfirmation;
|
|
311
|
+
|
|
312
|
+
if (!shouldCreateProject) {
|
|
313
|
+
const explanationString = i18n(
|
|
314
|
+
hasPublicApps
|
|
315
|
+
? `${i18nKey}.createNewProjectForLocalDev.publicAppProjectMustExistExplanation`
|
|
316
|
+
: `${i18nKey}.createNewProjectForLocalDev.projectMustExistExplanation`,
|
|
317
|
+
{
|
|
318
|
+
accountIdentifier: uiAccountDescription(targetAccountId),
|
|
319
|
+
projectName: projectConfig.name,
|
|
320
|
+
}
|
|
321
|
+
);
|
|
322
|
+
logger.log();
|
|
323
|
+
uiLine();
|
|
324
|
+
logger.log(explanationString);
|
|
325
|
+
uiLine();
|
|
326
|
+
|
|
327
|
+
shouldCreateProject = await confirmPrompt(
|
|
328
|
+
i18n(`${i18nKey}.createNewProjectForLocalDev.createProject`, {
|
|
329
|
+
accountIdentifier: uiAccountDescription(targetAccountId),
|
|
330
|
+
projectName: projectConfig.name,
|
|
331
|
+
})
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (shouldCreateProject) {
|
|
336
|
+
SpinniesManager.add('createProject', {
|
|
337
|
+
text: i18n(`${i18nKey}.createNewProjectForLocalDev.creatingProject`, {
|
|
338
|
+
accountIdentifier: uiAccountDescription(targetAccountId),
|
|
339
|
+
projectName: projectConfig.name,
|
|
340
|
+
}),
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
try {
|
|
344
|
+
const project = await createProject(targetAccountId, projectConfig.name);
|
|
345
|
+
SpinniesManager.succeed('createProject', {
|
|
346
|
+
text: i18n(`${i18nKey}.createNewProjectForLocalDev.createdProject`, {
|
|
347
|
+
accountIdentifier: uiAccountDescription(targetAccountId),
|
|
348
|
+
projectName: projectConfig.name,
|
|
349
|
+
}),
|
|
350
|
+
succeedColor: 'white',
|
|
351
|
+
});
|
|
352
|
+
return project;
|
|
353
|
+
} catch (err) {
|
|
354
|
+
SpinniesManager.fail('createProject');
|
|
355
|
+
logger.log(
|
|
356
|
+
i18n(`${i18nKey}.createNewProjectForLocalDev.failedToCreateProject`)
|
|
357
|
+
);
|
|
358
|
+
process.exit(EXIT_CODES.ERROR);
|
|
359
|
+
}
|
|
360
|
+
} else {
|
|
361
|
+
// We cannot continue if the project does not exist in the target account
|
|
362
|
+
logger.log();
|
|
363
|
+
logger.log(
|
|
364
|
+
i18n(`${i18nKey}.createNewProjectForLocalDev.choseNotToCreateProject`)
|
|
365
|
+
);
|
|
366
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
// Create an initial build if the project was newly created in the account
|
|
371
|
+
// Return the newly deployed build
|
|
372
|
+
const createInitialBuildForNewProject = async (
|
|
373
|
+
projectConfig,
|
|
374
|
+
projectDir,
|
|
375
|
+
targetAccountId
|
|
376
|
+
) => {
|
|
377
|
+
const initialUploadResult = await handleProjectUpload(
|
|
378
|
+
targetAccountId,
|
|
379
|
+
projectConfig,
|
|
380
|
+
projectDir,
|
|
381
|
+
(...args) => pollProjectBuildAndDeploy(...args, true),
|
|
382
|
+
i18n(`${i18nKey}.createInitialBuildForNewProject.initialUploadMessage`)
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
if (initialUploadResult.uploadError) {
|
|
386
|
+
if (
|
|
387
|
+
isSpecifiedError(initialUploadResult.uploadError, {
|
|
388
|
+
subCategory: PROJECT_ERROR_TYPES.PROJECT_LOCKED,
|
|
389
|
+
})
|
|
390
|
+
) {
|
|
391
|
+
logger.log();
|
|
392
|
+
logger.error(
|
|
393
|
+
i18n(`${i18nKey}.createInitialBuildForNewProject.projectLockedError`)
|
|
394
|
+
);
|
|
395
|
+
logger.log();
|
|
396
|
+
} else {
|
|
397
|
+
logApiErrorInstance(
|
|
398
|
+
initialUploadResult.uploadError,
|
|
399
|
+
new ApiErrorContext({
|
|
400
|
+
accountId: targetAccountId,
|
|
401
|
+
projectName: projectConfig.name,
|
|
402
|
+
})
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
process.exit(EXIT_CODES.ERROR);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (!initialUploadResult.succeeded) {
|
|
409
|
+
let subTasks = [];
|
|
410
|
+
|
|
411
|
+
if (initialUploadResult.buildResult.status === 'FAILURE') {
|
|
412
|
+
subTasks =
|
|
413
|
+
initialUploadResult.buildResult[PROJECT_BUILD_TEXT.SUBTASK_KEY];
|
|
414
|
+
} else if (initialUploadResult.deployResult.status === 'FAILURE') {
|
|
415
|
+
subTasks =
|
|
416
|
+
initialUploadResult.deployResult[PROJECT_DEPLOY_TEXT.SUBTASK_KEY];
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const failedSubTasks = subTasks.filter(task => task.status === 'FAILURE');
|
|
420
|
+
|
|
421
|
+
logger.log();
|
|
422
|
+
failedSubTasks.forEach(failedSubTask => {
|
|
423
|
+
logger.error(failedSubTask.errorMessage);
|
|
424
|
+
});
|
|
425
|
+
logger.log();
|
|
426
|
+
|
|
427
|
+
process.exit(EXIT_CODES.ERROR);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
return initialUploadResult.buildResult;
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
const getAccountHomeUrl = accountId => {
|
|
434
|
+
const baseUrl = getHubSpotWebsiteOrigin(
|
|
435
|
+
getEnv(accountId) === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD
|
|
436
|
+
);
|
|
437
|
+
return `${baseUrl}/home?portalId=${accountId}`;
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
module.exports = {
|
|
441
|
+
confirmDefaultAccountIsTarget,
|
|
442
|
+
checkIfAppDeveloperAccount,
|
|
443
|
+
checkIfDeveloperTestAccount,
|
|
444
|
+
suggestRecommendedNestedAccount,
|
|
445
|
+
createSandboxForLocalDev,
|
|
446
|
+
createDeveloperTestAccountForLocalDev,
|
|
447
|
+
useExistingDevTestAccount,
|
|
448
|
+
createNewProjectForLocalDev,
|
|
449
|
+
createInitialBuildForNewProject,
|
|
450
|
+
getAccountHomeUrl,
|
|
451
|
+
};
|
|
@@ -57,12 +57,20 @@ const fetchValidationResults = async (accountId, validationId) => {
|
|
|
57
57
|
}
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
-
const processValidationErrors = validationResults => {
|
|
60
|
+
const processValidationErrors = (i18nKey, validationResults) => {
|
|
61
61
|
if (validationResults.errors.length) {
|
|
62
|
-
const { errors } = validationResults;
|
|
62
|
+
const { assetPath, errors } = validationResults;
|
|
63
63
|
|
|
64
64
|
errors.forEach(err => {
|
|
65
|
-
|
|
65
|
+
if (err.failureReasonType === 'DOWNLOAD_EMPTY') {
|
|
66
|
+
logger.error(
|
|
67
|
+
i18n(`${i18nKey}.errors.invalidPath`, {
|
|
68
|
+
path: assetPath,
|
|
69
|
+
})
|
|
70
|
+
);
|
|
71
|
+
} else {
|
|
72
|
+
logger.error(`${err.context}`);
|
|
73
|
+
}
|
|
66
74
|
});
|
|
67
75
|
process.exit(EXIT_CODES.ERROR);
|
|
68
76
|
}
|
package/lib/polling.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const { POLLING_DELAY, POLLING_STATUS } = require('./constants');
|
|
2
|
+
|
|
3
|
+
const poll = (callback, accountId, taskId) => {
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
const pollInterval = setInterval(async () => {
|
|
6
|
+
const pollResp = await callback(accountId, taskId);
|
|
7
|
+
const { status } = pollResp;
|
|
8
|
+
|
|
9
|
+
if (status === POLLING_STATUS.SUCCESS) {
|
|
10
|
+
clearInterval(pollInterval);
|
|
11
|
+
resolve(pollResp);
|
|
12
|
+
} else if (
|
|
13
|
+
status === POLLING_STATUS.ERROR ||
|
|
14
|
+
status === POLLING_STATUS.REVERTED ||
|
|
15
|
+
status === POLLING_STATUS.FAILURE
|
|
16
|
+
) {
|
|
17
|
+
clearInterval(pollInterval);
|
|
18
|
+
reject(pollResp);
|
|
19
|
+
}
|
|
20
|
+
}, POLLING_DELAY);
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
module.exports = {
|
|
25
|
+
poll,
|
|
26
|
+
};
|
package/lib/process.js
CHANGED
package/lib/projectStructure.js
CHANGED
|
@@ -7,11 +7,13 @@ const { logErrorInstance } = require('./errorHandlers/standardErrors');
|
|
|
7
7
|
const COMPONENT_TYPES = Object.freeze({
|
|
8
8
|
privateApp: 'private-app',
|
|
9
9
|
publicApp: 'public-app',
|
|
10
|
+
hublTheme: 'hubl-theme',
|
|
10
11
|
});
|
|
11
12
|
|
|
12
13
|
const CONFIG_FILES = {
|
|
13
14
|
[COMPONENT_TYPES.privateApp]: 'app.json',
|
|
14
15
|
[COMPONENT_TYPES.publicApp]: 'public-app.json',
|
|
16
|
+
[COMPONENT_TYPES.hublTheme]: 'theme.json',
|
|
15
17
|
};
|
|
16
18
|
|
|
17
19
|
function getTypeFromConfigFile(configFile) {
|
|
@@ -102,13 +104,14 @@ async function findProjectComponents(projectSourceDir) {
|
|
|
102
104
|
if (Object.values(CONFIG_FILES).includes(base)) {
|
|
103
105
|
const parsedAppConfig = loadConfigFile(projectFile);
|
|
104
106
|
|
|
105
|
-
if (parsedAppConfig
|
|
107
|
+
if (parsedAppConfig) {
|
|
106
108
|
const isLegacy = getIsLegacyApp(parsedAppConfig, dir);
|
|
109
|
+
const isHublTheme = base === CONFIG_FILES[COMPONENT_TYPES.hublTheme];
|
|
107
110
|
|
|
108
111
|
components.push({
|
|
109
112
|
type: getTypeFromConfigFile(base),
|
|
110
113
|
config: parsedAppConfig,
|
|
111
|
-
runnable: !isLegacy,
|
|
114
|
+
runnable: !isLegacy && !isHublTheme,
|
|
112
115
|
path: dir,
|
|
113
116
|
});
|
|
114
117
|
}
|
|
@@ -118,9 +121,16 @@ async function findProjectComponents(projectSourceDir) {
|
|
|
118
121
|
return components;
|
|
119
122
|
}
|
|
120
123
|
|
|
124
|
+
function getProjectComponentTypes(components) {
|
|
125
|
+
const projectContents = {};
|
|
126
|
+
components.forEach(({ type }) => (projectContents[type] = true));
|
|
127
|
+
return projectContents;
|
|
128
|
+
}
|
|
129
|
+
|
|
121
130
|
module.exports = {
|
|
122
131
|
CONFIG_FILES,
|
|
123
132
|
COMPONENT_TYPES,
|
|
124
133
|
findProjectComponents,
|
|
125
134
|
getAppCardConfigs,
|
|
135
|
+
getProjectComponentTypes,
|
|
126
136
|
};
|