@hubspot/cli 4.0.1-beta.2 → 4.0.1-beta.5
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/README.md +1 -15
- package/bin/cli.js +2 -0
- package/commands/accounts/use.js +9 -26
- package/commands/auth.js +0 -22
- package/commands/cms/lighthouseScore.js +325 -0
- package/commands/cms.js +16 -0
- package/commands/fetch.js +7 -0
- package/commands/init.js +3 -19
- package/commands/project/logs.js +32 -6
- package/commands/sandbox/create.js +40 -22
- package/commands/sandbox/delete.js +133 -5
- package/hubspot.sample.config.yml +0 -7
- package/lib/__tests__/validation.js +0 -7
- package/lib/projects.js +15 -14
- package/lib/prompts/accountsPrompt.js +47 -0
- package/lib/prompts/personalAccessKeyPrompt.js +0 -15
- package/lib/prompts/sandboxesPrompt.js +19 -0
- package/lib/regex.js +0 -2
- package/lib/validation.js +7 -2
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -133,7 +133,7 @@ hs hubdb delete <id or name>
|
|
|
133
133
|
|
|
134
134
|
## Authentication
|
|
135
135
|
|
|
136
|
-
There are
|
|
136
|
+
There are two ways that the tools can authenticate with HubSpot.
|
|
137
137
|
|
|
138
138
|
### Personal Access Key (recommended)
|
|
139
139
|
|
|
@@ -146,20 +146,6 @@ There are three ways that the tools can authenticate with HubSpot.
|
|
|
146
146
|
3. Select `OAuth2` and follow the steps
|
|
147
147
|
|
|
148
148
|
_**Note:** The Account ID used should be the Test Account ID (not the developer app ID). Client ID and Client Secret are from the developer app._
|
|
149
|
-
|
|
150
|
-
### HubSpot API Key
|
|
151
|
-
|
|
152
|
-
1. [Set up an API Key for the Account](https://knowledge.hubspot.com/articles/kcs_article/integrations/how-do-i-get-my-hubspot-api-key)
|
|
153
|
-
2. Edit the [hubspot.config.yml](../../docs/HubspotConfigFile.md) file to set the `authType` for the account to `apikey` and add `apiKey` as shown below:
|
|
154
|
-
|
|
155
|
-
```yaml
|
|
156
|
-
defaultPortal: DEV
|
|
157
|
-
portals:
|
|
158
|
-
- name: DEV
|
|
159
|
-
portalId: 123
|
|
160
|
-
authType: apikey
|
|
161
|
-
apiKey: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
|
|
162
|
-
```
|
|
163
149
|
### Exit Codes
|
|
164
150
|
|
|
165
151
|
The CLI will exit with one of the following exit codes:
|
package/bin/cli.js
CHANGED
|
@@ -35,6 +35,7 @@ const moduleCommand = require('../commands/module');
|
|
|
35
35
|
const configCommand = require('../commands/config');
|
|
36
36
|
const accountsCommand = require('../commands/accounts');
|
|
37
37
|
const sandboxesCommand = require('../commands/sandbox');
|
|
38
|
+
const cmsCommand = require('../commands/cms');
|
|
38
39
|
const { EXIT_CODES } = require('../lib/enums/exitCodes');
|
|
39
40
|
|
|
40
41
|
const notifier = updateNotifier({ pkg: { ...pkg, name: '@hubspot/cli' } });
|
|
@@ -129,6 +130,7 @@ const argv = yargs
|
|
|
129
130
|
.command(authCommand)
|
|
130
131
|
.command(initCommand)
|
|
131
132
|
.command(logsCommand)
|
|
133
|
+
.command(cmsCommand)
|
|
132
134
|
.command(lintCommand)
|
|
133
135
|
.command(hubdbCommand)
|
|
134
136
|
.command(watchCommand)
|
package/commands/accounts/use.js
CHANGED
|
@@ -5,47 +5,24 @@ const {
|
|
|
5
5
|
updateDefaultAccount,
|
|
6
6
|
getAccountId: getAccountIdFromConfig,
|
|
7
7
|
} = require('@hubspot/cli-lib/lib/config');
|
|
8
|
-
const { loadAndValidateOptions } = require('../../lib/validation');
|
|
9
8
|
|
|
10
|
-
const { getAccountId } = require('../../lib/commonOpts');
|
|
11
9
|
const { trackCommandUsage } = require('../../lib/usageTracking');
|
|
12
|
-
const { promptUser } = require('../../lib/prompts/promptUtils');
|
|
13
10
|
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
11
|
+
const { selectAccountFromConfig } = require('../../lib/prompts/accountsPrompt');
|
|
12
|
+
const { loadAndValidateOptions } = require('../../lib/validation');
|
|
14
13
|
|
|
15
14
|
const i18nKey = 'cli.commands.accounts.subcommands.use';
|
|
16
15
|
|
|
17
|
-
const selectAccountFromConfig = async config => {
|
|
18
|
-
const { default: selectedDefault } = await promptUser([
|
|
19
|
-
{
|
|
20
|
-
type: 'list',
|
|
21
|
-
look: false,
|
|
22
|
-
name: 'default',
|
|
23
|
-
pageSize: 20,
|
|
24
|
-
message: i18n(`${i18nKey}.promptMessage`),
|
|
25
|
-
choices: config.portals.map(p => ({
|
|
26
|
-
name: `${p.name} (${p.portalId})`,
|
|
27
|
-
value: p.name || p.portalId,
|
|
28
|
-
})),
|
|
29
|
-
default: config.defaultPortal,
|
|
30
|
-
},
|
|
31
|
-
]);
|
|
32
|
-
|
|
33
|
-
return selectedDefault;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
16
|
exports.command = 'use [--account]';
|
|
37
17
|
exports.describe = i18n(`${i18nKey}.describe`);
|
|
38
18
|
|
|
39
19
|
exports.handler = async options => {
|
|
40
|
-
await loadAndValidateOptions(
|
|
20
|
+
await loadAndValidateOptions(options, false);
|
|
41
21
|
|
|
42
|
-
const accountId = getAccountId(options);
|
|
43
22
|
const config = getConfig();
|
|
44
23
|
|
|
45
24
|
let newDefaultAccount = options.account;
|
|
46
25
|
|
|
47
|
-
trackCommandUsage('accounts-use', {}, accountId);
|
|
48
|
-
|
|
49
26
|
if (!newDefaultAccount) {
|
|
50
27
|
newDefaultAccount = await selectAccountFromConfig(config);
|
|
51
28
|
} else if (!getAccountIdFromConfig(newDefaultAccount)) {
|
|
@@ -58,6 +35,12 @@ exports.handler = async options => {
|
|
|
58
35
|
newDefaultAccount = await selectAccountFromConfig(config);
|
|
59
36
|
}
|
|
60
37
|
|
|
38
|
+
trackCommandUsage(
|
|
39
|
+
'accounts-use',
|
|
40
|
+
{},
|
|
41
|
+
getAccountIdFromConfig(newDefaultAccount)
|
|
42
|
+
);
|
|
43
|
+
|
|
61
44
|
updateDefaultAccount(newDefaultAccount);
|
|
62
45
|
|
|
63
46
|
return logger.success(
|
package/commands/auth.js
CHANGED
|
@@ -3,7 +3,6 @@ const { logger } = require('@hubspot/cli-lib/logger');
|
|
|
3
3
|
const {
|
|
4
4
|
OAUTH_AUTH_METHOD,
|
|
5
5
|
PERSONAL_ACCESS_KEY_AUTH_METHOD,
|
|
6
|
-
API_KEY_AUTH_METHOD,
|
|
7
6
|
ENVIRONMENTS,
|
|
8
7
|
DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME,
|
|
9
8
|
} = require('@hubspot/cli-lib/lib/constants');
|
|
@@ -22,7 +21,6 @@ const { promptUser } = require('../lib/prompts/promptUtils');
|
|
|
22
21
|
const {
|
|
23
22
|
personalAccessKeyPrompt,
|
|
24
23
|
OAUTH_FLOW,
|
|
25
|
-
API_KEY_FLOW,
|
|
26
24
|
} = require('../lib/prompts/personalAccessKeyPrompt');
|
|
27
25
|
const {
|
|
28
26
|
enterAccountNamePrompt,
|
|
@@ -80,25 +78,6 @@ exports.handler = async options => {
|
|
|
80
78
|
let successAuthMethod;
|
|
81
79
|
|
|
82
80
|
switch (authType) {
|
|
83
|
-
case API_KEY_AUTH_METHOD.value:
|
|
84
|
-
configData = await promptUser(API_KEY_FLOW);
|
|
85
|
-
updatedConfig = await updateAccountConfig(configData);
|
|
86
|
-
validName = updatedConfig.name;
|
|
87
|
-
|
|
88
|
-
if (!validName) {
|
|
89
|
-
const { name: namePrompt } = await enterAccountNamePrompt();
|
|
90
|
-
validName = namePrompt;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
updateAccountConfig({
|
|
94
|
-
...updatedConfig,
|
|
95
|
-
environment: updatedConfig.env,
|
|
96
|
-
name: validName,
|
|
97
|
-
});
|
|
98
|
-
writeConfig();
|
|
99
|
-
|
|
100
|
-
successAuthMethod = API_KEY_AUTH_METHOD.name;
|
|
101
|
-
break;
|
|
102
81
|
case OAUTH_AUTH_METHOD.value:
|
|
103
82
|
configData = await promptUser(OAUTH_FLOW);
|
|
104
83
|
await authenticateWithOauth({
|
|
@@ -188,7 +167,6 @@ exports.builder = yargs => {
|
|
|
188
167
|
choices: [
|
|
189
168
|
`${PERSONAL_ACCESS_KEY_AUTH_METHOD.value}`,
|
|
190
169
|
`${OAUTH_AUTH_METHOD.value}`,
|
|
191
|
-
`${API_KEY_AUTH_METHOD.value}`,
|
|
192
170
|
],
|
|
193
171
|
default: PERSONAL_ACCESS_KEY_AUTH_METHOD.value,
|
|
194
172
|
defaultDescription: i18n(`${i18nKey}.positionals.type.defaultDescription`, {
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
//const chalk = require('chalk');
|
|
2
|
+
const Spinnies = require('spinnies');
|
|
3
|
+
const {
|
|
4
|
+
addAccountOptions,
|
|
5
|
+
addConfigOptions,
|
|
6
|
+
addUseEnvironmentOptions,
|
|
7
|
+
getAccountId,
|
|
8
|
+
} = require('../../lib/commonOpts');
|
|
9
|
+
const { logger } = require('@hubspot/cli-lib/logger');
|
|
10
|
+
const {
|
|
11
|
+
getTableContents,
|
|
12
|
+
getTableHeader,
|
|
13
|
+
} = require('@hubspot/cli-lib/lib/table');
|
|
14
|
+
const { loadAndValidateOptions } = require('../../lib/validation');
|
|
15
|
+
const { promptUser } = require('../../lib/prompts/promptUtils');
|
|
16
|
+
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
17
|
+
const { fetchThemes } = require('@hubspot/cli-lib/api/designManager');
|
|
18
|
+
const {
|
|
19
|
+
requestLighthouseScore,
|
|
20
|
+
getLighthouseScoreStatus,
|
|
21
|
+
getLighthouseScore,
|
|
22
|
+
} = require('@hubspot/cli-lib/api/lighthouseScore');
|
|
23
|
+
const {
|
|
24
|
+
HUBSPOT_FOLDER,
|
|
25
|
+
MARKETPLACE_FOLDER,
|
|
26
|
+
} = require('@hubspot/cli-lib/lib/constants');
|
|
27
|
+
const { uiLink } = require('../../lib/ui');
|
|
28
|
+
const { EXIT_CODES } = require('../../lib/enums/exitCodes');
|
|
29
|
+
|
|
30
|
+
const i18nKey = 'cli.commands.cms.subcommands.lighthouseScore';
|
|
31
|
+
|
|
32
|
+
const DEFAULT_TABLE_HEADER = [
|
|
33
|
+
'Accessibility',
|
|
34
|
+
'Best practices',
|
|
35
|
+
'Performace',
|
|
36
|
+
'PWA',
|
|
37
|
+
'SEO',
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
exports.command = 'lighthouse-score [--theme]';
|
|
41
|
+
exports.describe = i18n(`${i18nKey}.describe`);
|
|
42
|
+
|
|
43
|
+
const selectTheme = async accountId => {
|
|
44
|
+
const { theme: selectedTheme } = await promptUser([
|
|
45
|
+
{
|
|
46
|
+
type: 'list',
|
|
47
|
+
look: false,
|
|
48
|
+
name: 'theme',
|
|
49
|
+
message: i18n(`${i18nKey}.info.promptMessage`),
|
|
50
|
+
choices: async () => {
|
|
51
|
+
try {
|
|
52
|
+
const result = await fetchThemes(accountId, {
|
|
53
|
+
limit: 500,
|
|
54
|
+
sorting: 'MOST_USED',
|
|
55
|
+
});
|
|
56
|
+
if (result && result.objects) {
|
|
57
|
+
return result.objects
|
|
58
|
+
.map(({ theme }) => theme.path)
|
|
59
|
+
.filter(
|
|
60
|
+
themePath =>
|
|
61
|
+
!themePath.startsWith(HUBSPOT_FOLDER) &&
|
|
62
|
+
!themePath.startsWith(MARKETPLACE_FOLDER)
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
} catch (err) {
|
|
66
|
+
logger.error(i18n(`${i18nKey}.errors.failedToFetchThemes`));
|
|
67
|
+
process.exit(EXIT_CODES.ERROR);
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
]);
|
|
72
|
+
|
|
73
|
+
return selectedTheme;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
exports.handler = async options => {
|
|
77
|
+
await loadAndValidateOptions(options);
|
|
78
|
+
const accountId = getAccountId(options);
|
|
79
|
+
|
|
80
|
+
const includeDesktopScore = options.target === 'desktop' || !options.verbose;
|
|
81
|
+
const includeMobileScore = options.target === 'mobile' || !options.verbose;
|
|
82
|
+
let themeToCheck = options.theme;
|
|
83
|
+
|
|
84
|
+
if (themeToCheck) {
|
|
85
|
+
let isValidTheme = true;
|
|
86
|
+
try {
|
|
87
|
+
const result = await fetchThemes(accountId, {
|
|
88
|
+
name: encodeURIComponent(themeToCheck),
|
|
89
|
+
});
|
|
90
|
+
isValidTheme = result && result.total;
|
|
91
|
+
} catch (err) {
|
|
92
|
+
isValidTheme = false;
|
|
93
|
+
}
|
|
94
|
+
if (!isValidTheme) {
|
|
95
|
+
logger.error(
|
|
96
|
+
i18n(`${i18nKey}.errors.themeNotFound`, { theme: themeToCheck })
|
|
97
|
+
);
|
|
98
|
+
process.exit(EXIT_CODES.ERROR);
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
themeToCheck = await selectTheme(accountId);
|
|
102
|
+
logger.log();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Kick off the scoring
|
|
106
|
+
let requestResult;
|
|
107
|
+
try {
|
|
108
|
+
requestResult = await requestLighthouseScore(accountId, {
|
|
109
|
+
themePath: themeToCheck,
|
|
110
|
+
});
|
|
111
|
+
} catch (err) {
|
|
112
|
+
logger.debug(err);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (!requestResult || !requestResult.mobileId || !requestResult.desktopId) {
|
|
116
|
+
logger.error(i18n(`${i18nKey}.errors.failedToGetLighthouseScore`));
|
|
117
|
+
process.exit(EXIT_CODES.ERROR);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Poll till scoring is finished
|
|
121
|
+
try {
|
|
122
|
+
const spinnies = new Spinnies();
|
|
123
|
+
|
|
124
|
+
spinnies.add('lighthouseScore', {
|
|
125
|
+
text: i18n(`${i18nKey}.info.generatingScore`, { theme: themeToCheck }),
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const checkScoreStatus = async () => {
|
|
129
|
+
const desktopScoreStatus = includeDesktopScore
|
|
130
|
+
? await getLighthouseScoreStatus(accountId, {
|
|
131
|
+
themeId: requestResult.desktopId,
|
|
132
|
+
})
|
|
133
|
+
: 'COMPLETED';
|
|
134
|
+
const mobileScoreStatus = includeMobileScore
|
|
135
|
+
? await getLighthouseScoreStatus(accountId, {
|
|
136
|
+
themeId: requestResult.mobileId,
|
|
137
|
+
})
|
|
138
|
+
: 'COMPLETED';
|
|
139
|
+
|
|
140
|
+
if (
|
|
141
|
+
desktopScoreStatus === 'REQUESTED' ||
|
|
142
|
+
mobileScoreStatus === 'REQUESTED'
|
|
143
|
+
) {
|
|
144
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
145
|
+
await checkScoreStatus();
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
await checkScoreStatus();
|
|
150
|
+
|
|
151
|
+
spinnies.remove('lighthouseScore');
|
|
152
|
+
} catch (err) {
|
|
153
|
+
logger.debug(err);
|
|
154
|
+
process.exit(EXIT_CODES.ERROR);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Fetch the scoring results
|
|
158
|
+
let desktopScoreResult;
|
|
159
|
+
let mobileScoreResult;
|
|
160
|
+
let verboseViewAverageScoreResult;
|
|
161
|
+
try {
|
|
162
|
+
const params = { isAverage: !options.verbose };
|
|
163
|
+
desktopScoreResult = includeDesktopScore
|
|
164
|
+
? await getLighthouseScore(accountId, {
|
|
165
|
+
...params,
|
|
166
|
+
desktopId: requestResult.desktopId,
|
|
167
|
+
})
|
|
168
|
+
: {};
|
|
169
|
+
mobileScoreResult = includeMobileScore
|
|
170
|
+
? await getLighthouseScore(accountId, {
|
|
171
|
+
...params,
|
|
172
|
+
mobileId: requestResult.mobileId,
|
|
173
|
+
})
|
|
174
|
+
: {};
|
|
175
|
+
// This is needed to show the average scores above the verbose output
|
|
176
|
+
verboseViewAverageScoreResult = options.verbose
|
|
177
|
+
? await getLighthouseScore(accountId, {
|
|
178
|
+
...params,
|
|
179
|
+
isAverage: true,
|
|
180
|
+
desktopId: includeDesktopScore ? requestResult.desktopId : null,
|
|
181
|
+
mobileId: includeMobileScore ? requestResult.mobileId : null,
|
|
182
|
+
})
|
|
183
|
+
: {};
|
|
184
|
+
} catch (err) {
|
|
185
|
+
logger.error(i18n(`${i18nKey}.errors.failedToGetLighthouseScore`));
|
|
186
|
+
process.exit(EXIT_CODES.ERROR);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (options.verbose) {
|
|
190
|
+
logger.log(`${themeToCheck} ${options.target} scores`);
|
|
191
|
+
|
|
192
|
+
const tableHeader = getTableHeader(DEFAULT_TABLE_HEADER);
|
|
193
|
+
|
|
194
|
+
const scores = verboseViewAverageScoreResult.scores
|
|
195
|
+
? verboseViewAverageScoreResult.scores[0]
|
|
196
|
+
: {};
|
|
197
|
+
|
|
198
|
+
const averageTableData = [
|
|
199
|
+
scores.accessibilityScore,
|
|
200
|
+
scores.bestPracticesScore,
|
|
201
|
+
scores.performanceScore,
|
|
202
|
+
scores.pwaScore,
|
|
203
|
+
scores.seoScore,
|
|
204
|
+
];
|
|
205
|
+
|
|
206
|
+
logger.log(
|
|
207
|
+
getTableContents([tableHeader, averageTableData], {
|
|
208
|
+
border: { bodyLeft: ' ' },
|
|
209
|
+
})
|
|
210
|
+
);
|
|
211
|
+
logger.log(i18n(`${i18nKey}.info.pageTemplateScoreTitle`));
|
|
212
|
+
|
|
213
|
+
const table2Header = getTableHeader([
|
|
214
|
+
'Template path',
|
|
215
|
+
...DEFAULT_TABLE_HEADER,
|
|
216
|
+
]);
|
|
217
|
+
|
|
218
|
+
const scoreResult =
|
|
219
|
+
options.target === 'desktop' ? desktopScoreResult : mobileScoreResult;
|
|
220
|
+
|
|
221
|
+
const templateTableData = scoreResult.scores.map(score => {
|
|
222
|
+
return [
|
|
223
|
+
score.templatePath,
|
|
224
|
+
score.accessibilityScore,
|
|
225
|
+
score.bestPracticesScore,
|
|
226
|
+
score.performanceScore,
|
|
227
|
+
score.pwaScore,
|
|
228
|
+
score.seoScore,
|
|
229
|
+
];
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
logger.log(
|
|
233
|
+
getTableContents([table2Header, ...templateTableData], {
|
|
234
|
+
border: { bodyLeft: ' ' },
|
|
235
|
+
})
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
logger.log(i18n(`${i18nKey}.info.lighthouseLinksTitle`));
|
|
239
|
+
|
|
240
|
+
scoreResult.scores.forEach(score => {
|
|
241
|
+
logger.log(' ', uiLink(score.templatePath, score.link));
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
if (scoreResult.failedTemplatePaths.length) {
|
|
245
|
+
logger.log();
|
|
246
|
+
logger.error(i18n(`${i18nKey}.info.failedTemplatePathsTitle`));
|
|
247
|
+
scoreResult.failedTemplatePaths.forEach(failedTemplatePath => {
|
|
248
|
+
logger.log(' ', failedTemplatePath);
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
logger.log();
|
|
253
|
+
logger.info(
|
|
254
|
+
i18n(`${i18nKey}.info.targetDeviceNote`, { target: options.target })
|
|
255
|
+
);
|
|
256
|
+
} else {
|
|
257
|
+
logger.log(`Theme: ${themeToCheck}`);
|
|
258
|
+
const tableHeader = getTableHeader(['Target', ...DEFAULT_TABLE_HEADER]);
|
|
259
|
+
|
|
260
|
+
const getTableData = (target, scoreResult) => {
|
|
261
|
+
const scores = scoreResult.scores ? scoreResult.scores[0] : {};
|
|
262
|
+
return [
|
|
263
|
+
target,
|
|
264
|
+
scores.accessibilityScore,
|
|
265
|
+
scores.bestPracticesScore,
|
|
266
|
+
scores.performanceScore,
|
|
267
|
+
scores.pwaScore,
|
|
268
|
+
scores.seoScore,
|
|
269
|
+
];
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const tableData = [
|
|
273
|
+
getTableData('desktop', desktopScoreResult),
|
|
274
|
+
getTableData('mobile', mobileScoreResult),
|
|
275
|
+
];
|
|
276
|
+
|
|
277
|
+
logger.log(
|
|
278
|
+
getTableContents([tableHeader, ...tableData], {
|
|
279
|
+
border: { bodyLeft: ' ' },
|
|
280
|
+
})
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
logger.info(i18n(`${i18nKey}.info.verboseOptionNote`));
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
logger.log();
|
|
287
|
+
logger.log(
|
|
288
|
+
`Powered by ${uiLink(
|
|
289
|
+
'Google Lighthouse',
|
|
290
|
+
'https://developer.chrome.com/docs/lighthouse/overview/'
|
|
291
|
+
)}.`
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
process.exit();
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
exports.builder = yargs => {
|
|
298
|
+
yargs.option('theme', {
|
|
299
|
+
describe: i18n(`${i18nKey}.options.theme.describe`),
|
|
300
|
+
type: 'string',
|
|
301
|
+
});
|
|
302
|
+
yargs.option('target', {
|
|
303
|
+
describe: i18n(`${i18nKey}.options.target.describe`),
|
|
304
|
+
type: 'string',
|
|
305
|
+
choices: ['desktop', 'mobile'],
|
|
306
|
+
default: 'desktop',
|
|
307
|
+
});
|
|
308
|
+
yargs.option('verbose', {
|
|
309
|
+
describe: i18n(`${i18nKey}.options.verbose.describe`),
|
|
310
|
+
boolean: true,
|
|
311
|
+
default: false,
|
|
312
|
+
});
|
|
313
|
+
yargs.example([
|
|
314
|
+
[
|
|
315
|
+
'$0 cms lighthouse-score --theme=my-theme',
|
|
316
|
+
i18n(`${i18nKey}.examples.default`),
|
|
317
|
+
],
|
|
318
|
+
]);
|
|
319
|
+
|
|
320
|
+
addConfigOptions(yargs, true);
|
|
321
|
+
addAccountOptions(yargs, true);
|
|
322
|
+
addUseEnvironmentOptions(yargs, true);
|
|
323
|
+
|
|
324
|
+
return yargs;
|
|
325
|
+
};
|
package/commands/cms.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const { addConfigOptions, addAccountOptions } = require('../lib/commonOpts');
|
|
2
|
+
const lighthouseScore = require('./cms/lighthouseScore');
|
|
3
|
+
|
|
4
|
+
// const i18nKey = 'cli.commands.cms';
|
|
5
|
+
|
|
6
|
+
exports.command = 'cms';
|
|
7
|
+
exports.describe = false; // i18n(`${i18nKey}.describe`);
|
|
8
|
+
|
|
9
|
+
exports.builder = yargs => {
|
|
10
|
+
addConfigOptions(yargs, true);
|
|
11
|
+
addAccountOptions(yargs, true);
|
|
12
|
+
|
|
13
|
+
yargs.command(lighthouseScore).demandCommand(1, '');
|
|
14
|
+
|
|
15
|
+
return yargs;
|
|
16
|
+
};
|
package/commands/fetch.js
CHANGED
package/commands/init.js
CHANGED
|
@@ -5,17 +5,15 @@ const {
|
|
|
5
5
|
createEmptyConfigFile,
|
|
6
6
|
deleteEmptyConfigFile,
|
|
7
7
|
updateDefaultAccount,
|
|
8
|
-
writeConfig,
|
|
9
|
-
updateAccountConfig,
|
|
10
8
|
} = require('@hubspot/cli-lib/lib/config');
|
|
11
9
|
const { addConfigOptions } = require('../lib/commonOpts');
|
|
12
10
|
const { handleExit } = require('@hubspot/cli-lib/lib/process');
|
|
11
|
+
const { checkAndUpdateGitignore } = require('@hubspot/cli-lib/lib/git');
|
|
13
12
|
const { logErrorInstance } = require('@hubspot/cli-lib/errorHandlers');
|
|
14
13
|
const {
|
|
15
14
|
DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME,
|
|
16
15
|
PERSONAL_ACCESS_KEY_AUTH_METHOD,
|
|
17
16
|
OAUTH_AUTH_METHOD,
|
|
18
|
-
API_KEY_AUTH_METHOD,
|
|
19
17
|
ENVIRONMENTS,
|
|
20
18
|
} = require('@hubspot/cli-lib/lib/constants');
|
|
21
19
|
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
@@ -29,7 +27,6 @@ const { setLogLevel, addTestingOptions } = require('../lib/commonOpts');
|
|
|
29
27
|
const { promptUser } = require('../lib/prompts/promptUtils');
|
|
30
28
|
const {
|
|
31
29
|
OAUTH_FLOW,
|
|
32
|
-
API_KEY_FLOW,
|
|
33
30
|
personalAccessKeyPrompt,
|
|
34
31
|
} = require('../lib/prompts/personalAccessKeyPrompt');
|
|
35
32
|
const {
|
|
@@ -70,28 +67,14 @@ const oauthConfigCreationFlow = async env => {
|
|
|
70
67
|
return accountConfig;
|
|
71
68
|
};
|
|
72
69
|
|
|
73
|
-
const apiKeyConfigCreationFlow = async env => {
|
|
74
|
-
const configData = await promptUser(API_KEY_FLOW);
|
|
75
|
-
const accountConfig = {
|
|
76
|
-
...configData,
|
|
77
|
-
env,
|
|
78
|
-
};
|
|
79
|
-
updateAccountConfig(accountConfig);
|
|
80
|
-
updateDefaultAccount(accountConfig.name);
|
|
81
|
-
writeConfig();
|
|
82
|
-
return accountConfig;
|
|
83
|
-
};
|
|
84
|
-
|
|
85
70
|
const CONFIG_CREATION_FLOWS = {
|
|
86
71
|
[PERSONAL_ACCESS_KEY_AUTH_METHOD.value]: personalAccessKeyConfigCreationFlow,
|
|
87
72
|
[OAUTH_AUTH_METHOD.value]: oauthConfigCreationFlow,
|
|
88
|
-
[API_KEY_AUTH_METHOD.value]: apiKeyConfigCreationFlow,
|
|
89
73
|
};
|
|
90
74
|
|
|
91
75
|
const AUTH_TYPE_NAMES = {
|
|
92
76
|
[PERSONAL_ACCESS_KEY_AUTH_METHOD.value]: PERSONAL_ACCESS_KEY_AUTH_METHOD.name,
|
|
93
77
|
[OAUTH_AUTH_METHOD.value]: OAUTH_AUTH_METHOD.name,
|
|
94
|
-
[API_KEY_AUTH_METHOD.value]: API_KEY_AUTH_METHOD.name,
|
|
95
78
|
};
|
|
96
79
|
|
|
97
80
|
exports.command = 'init [--account]';
|
|
@@ -134,6 +117,8 @@ exports.handler = async options => {
|
|
|
134
117
|
);
|
|
135
118
|
const configPath = getConfigPath();
|
|
136
119
|
|
|
120
|
+
checkAndUpdateGitignore(configPath);
|
|
121
|
+
|
|
137
122
|
logger.log('');
|
|
138
123
|
logger.success(
|
|
139
124
|
i18n(`${i18nKey}.success.configFileCreated`, {
|
|
@@ -164,7 +149,6 @@ exports.builder = yargs => {
|
|
|
164
149
|
choices: [
|
|
165
150
|
`${PERSONAL_ACCESS_KEY_AUTH_METHOD.value}`,
|
|
166
151
|
`${OAUTH_AUTH_METHOD.value}`,
|
|
167
|
-
`${API_KEY_AUTH_METHOD.value}`,
|
|
168
152
|
],
|
|
169
153
|
default: PERSONAL_ACCESS_KEY_AUTH_METHOD.value,
|
|
170
154
|
defaultDescription: i18n(`${i18nKey}.options.auth.defaultDescription`, {
|
package/commands/project/logs.js
CHANGED
|
@@ -10,7 +10,10 @@ const {
|
|
|
10
10
|
const { trackCommandUsage } = require('../../lib/usageTracking');
|
|
11
11
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
12
12
|
const { outputLogs } = require('@hubspot/cli-lib/lib/logs');
|
|
13
|
-
const {
|
|
13
|
+
const {
|
|
14
|
+
fetchProject,
|
|
15
|
+
fetchDeployComponentsMetadata,
|
|
16
|
+
} = require('@hubspot/cli-lib/api/dfs');
|
|
14
17
|
const {
|
|
15
18
|
getTableContents,
|
|
16
19
|
getTableHeader,
|
|
@@ -142,12 +145,30 @@ exports.handler = async options => {
|
|
|
142
145
|
const endpointName = options.endpoint || promptEndpointName;
|
|
143
146
|
|
|
144
147
|
let relativeAppPath;
|
|
148
|
+
let appId;
|
|
145
149
|
|
|
146
150
|
if (appName && !endpointName) {
|
|
147
151
|
await ensureProjectExists(accountId, projectName, {
|
|
148
152
|
allowCreate: false,
|
|
149
153
|
});
|
|
150
|
-
|
|
154
|
+
|
|
155
|
+
const { deployedBuild, id: projectId } = await fetchProject(
|
|
156
|
+
accountId,
|
|
157
|
+
projectName
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
const { results: deployComponents } = await fetchDeployComponentsMetadata(
|
|
161
|
+
accountId,
|
|
162
|
+
projectId
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
const appComponent = deployComponents.find(
|
|
166
|
+
c => c.componentName === appName
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
if (appComponent) {
|
|
170
|
+
appId = appComponent.componentIdentifier;
|
|
171
|
+
}
|
|
151
172
|
|
|
152
173
|
if (deployedBuild && deployedBuild.subbuildStatuses) {
|
|
153
174
|
const appSubbuild = deployedBuild.subbuildStatuses.find(
|
|
@@ -196,10 +217,15 @@ exports.handler = async options => {
|
|
|
196
217
|
);
|
|
197
218
|
|
|
198
219
|
logger.log(
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
220
|
+
appId
|
|
221
|
+
? uiLink(
|
|
222
|
+
i18n(`${i18nKey}.logs.hubspotLogsDirectLink`),
|
|
223
|
+
`${getPrivateAppsUrl(accountId)}/${appId}/logs/extensions`
|
|
224
|
+
)
|
|
225
|
+
: uiLink(
|
|
226
|
+
i18n(`${i18nKey}.logs.hubspotLogsLink`),
|
|
227
|
+
getPrivateAppsUrl(accountId)
|
|
228
|
+
)
|
|
203
229
|
);
|
|
204
230
|
logger.log();
|
|
205
231
|
uiLine();
|
|
@@ -7,12 +7,15 @@ const {
|
|
|
7
7
|
} = require('../../lib/commonOpts');
|
|
8
8
|
const { trackCommandUsage } = require('../../lib/usageTracking');
|
|
9
9
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
10
|
-
|
|
10
|
+
const Spinnies = require('spinnies');
|
|
11
11
|
const { createSandbox } = require('@hubspot/cli-lib/sandboxes');
|
|
12
12
|
const { loadAndValidateOptions } = require('../../lib/validation');
|
|
13
13
|
const { createSandboxPrompt } = require('../../lib/prompts/sandboxesPrompt');
|
|
14
14
|
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
15
15
|
const { logErrorInstance } = require('@hubspot/cli-lib/errorHandlers');
|
|
16
|
+
const {
|
|
17
|
+
debugErrorAndContext,
|
|
18
|
+
} = require('@hubspot/cli-lib/errorHandlers/standardErrors');
|
|
16
19
|
const {
|
|
17
20
|
ENVIRONMENTS,
|
|
18
21
|
PERSONAL_ACCESS_KEY_AUTH_METHOD,
|
|
@@ -103,7 +106,7 @@ const personalAccessKeyFlow = async (env, account, name) => {
|
|
|
103
106
|
]);
|
|
104
107
|
};
|
|
105
108
|
|
|
106
|
-
exports.command = 'create [name]';
|
|
109
|
+
exports.command = 'create [--name]';
|
|
107
110
|
exports.describe = i18n(`${i18nKey}.describe`);
|
|
108
111
|
|
|
109
112
|
exports.handler = async options => {
|
|
@@ -113,6 +116,10 @@ exports.handler = async options => {
|
|
|
113
116
|
const accountId = getAccountId(options);
|
|
114
117
|
const accountConfig = getAccountConfig(accountId);
|
|
115
118
|
const env = options.qa ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD;
|
|
119
|
+
const spinnies = new Spinnies({
|
|
120
|
+
succeedColor: 'white',
|
|
121
|
+
});
|
|
122
|
+
|
|
116
123
|
let namePrompt;
|
|
117
124
|
|
|
118
125
|
trackCommandUsage('sandbox-create', {}, accountId);
|
|
@@ -123,26 +130,33 @@ exports.handler = async options => {
|
|
|
123
130
|
|
|
124
131
|
const sandboxName = name || namePrompt.name;
|
|
125
132
|
|
|
126
|
-
logger.debug(
|
|
127
|
-
i18n(`${i18nKey}.debug.creating`, {
|
|
128
|
-
name: sandboxName,
|
|
129
|
-
})
|
|
130
|
-
);
|
|
131
133
|
let result;
|
|
134
|
+
|
|
132
135
|
try {
|
|
133
|
-
|
|
134
|
-
({
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
|
|
136
|
+
spinnies.add('sandboxCreate', {
|
|
137
|
+
text: i18n(`${i18nKey}.loading.add`, {
|
|
138
|
+
sandboxName,
|
|
139
|
+
}),
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
result = await createSandbox(accountId, sandboxName);
|
|
143
|
+
|
|
144
|
+
logger.log('');
|
|
145
|
+
spinnies.succeed('sandboxCreate', {
|
|
146
|
+
text: i18n(`${i18nKey}.loading.succeed`, {
|
|
147
|
+
name: result.name,
|
|
148
|
+
sandboxHubId: result.sandboxHubId,
|
|
149
|
+
}),
|
|
150
|
+
});
|
|
145
151
|
} catch (err) {
|
|
152
|
+
debugErrorAndContext(err);
|
|
153
|
+
|
|
154
|
+
spinnies.fail('sandboxCreate', {
|
|
155
|
+
text: i18n(`${i18nKey}.loading.fail`, {
|
|
156
|
+
sandboxName,
|
|
157
|
+
}),
|
|
158
|
+
});
|
|
159
|
+
|
|
146
160
|
if (isMissingScopeError(err)) {
|
|
147
161
|
logger.error(
|
|
148
162
|
i18n(`${i18nKey}.failure.scopes.message`, {
|
|
@@ -167,17 +181,21 @@ exports.handler = async options => {
|
|
|
167
181
|
process.exit(EXIT_CODES.SUCCESS);
|
|
168
182
|
} catch (err) {
|
|
169
183
|
logErrorInstance(err);
|
|
184
|
+
process.exit(EXIT_CODES.ERROR);
|
|
170
185
|
}
|
|
171
186
|
};
|
|
172
187
|
|
|
173
188
|
exports.builder = yargs => {
|
|
174
|
-
yargs.
|
|
175
|
-
describe: i18n(`${i18nKey}.
|
|
189
|
+
yargs.option('name', {
|
|
190
|
+
describe: i18n(`${i18nKey}.options.name.describe`),
|
|
176
191
|
type: 'string',
|
|
177
192
|
});
|
|
178
193
|
|
|
179
194
|
yargs.example([
|
|
180
|
-
[
|
|
195
|
+
[
|
|
196
|
+
'$0 sandbox create --name=MySandboxAccount',
|
|
197
|
+
i18n(`${i18nKey}.examples.default`),
|
|
198
|
+
],
|
|
181
199
|
]);
|
|
182
200
|
|
|
183
201
|
addConfigOptions(yargs, true);
|
|
@@ -2,22 +2,149 @@ const {
|
|
|
2
2
|
addAccountOptions,
|
|
3
3
|
addConfigOptions,
|
|
4
4
|
addUseEnvironmentOptions,
|
|
5
|
+
getAccountId,
|
|
6
|
+
addTestingOptions,
|
|
5
7
|
} = require('../../lib/commonOpts');
|
|
6
8
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
7
|
-
|
|
9
|
+
const { trackCommandUsage } = require('../../lib/usageTracking');
|
|
8
10
|
const { loadAndValidateOptions } = require('../../lib/validation');
|
|
11
|
+
const {
|
|
12
|
+
debugErrorAndContext,
|
|
13
|
+
} = require('@hubspot/cli-lib/errorHandlers/standardErrors');
|
|
14
|
+
|
|
15
|
+
const { deleteSandbox } = require('@hubspot/cli-lib/sandboxes');
|
|
9
16
|
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
17
|
+
const { getConfig, getEnv } = require('@hubspot/cli-lib');
|
|
18
|
+
const { deleteSandboxPrompt } = require('../../lib/prompts/sandboxesPrompt');
|
|
19
|
+
const { removeAccountFromConfig } = require('@hubspot/cli-lib/lib/config');
|
|
20
|
+
const {
|
|
21
|
+
selectAndSetAsDefaultAccountPrompt,
|
|
22
|
+
} = require('../../lib/prompts/accountsPrompt');
|
|
23
|
+
const { EXIT_CODES } = require('../../lib/enums/exitCodes');
|
|
24
|
+
const { promptUser } = require('../../lib/prompts/promptUtils');
|
|
25
|
+
const { getHubSpotWebsiteOrigin } = require('@hubspot/cli-lib/lib/urls');
|
|
26
|
+
const { ENVIRONMENTS } = require('@hubspot/cli-lib/lib/constants');
|
|
10
27
|
|
|
11
28
|
const i18nKey = 'cli.commands.sandbox.subcommands.delete';
|
|
12
29
|
|
|
13
|
-
|
|
30
|
+
const SANDBOX_NOT_FOUND = 'SandboxErrors.SANDBOX_NOT_FOUND';
|
|
31
|
+
const OBJECT_NOT_FOUND = 'OBJECT_NOT_FOUND';
|
|
32
|
+
|
|
33
|
+
exports.command = 'delete [--account]';
|
|
14
34
|
exports.describe = i18n(`${i18nKey}.describe`);
|
|
15
35
|
|
|
16
36
|
exports.handler = async options => {
|
|
17
|
-
await loadAndValidateOptions(options);
|
|
37
|
+
await loadAndValidateOptions(options, false);
|
|
38
|
+
|
|
39
|
+
const { account } = options;
|
|
40
|
+
const config = getConfig();
|
|
41
|
+
|
|
42
|
+
let accountPrompt;
|
|
43
|
+
if (!account) {
|
|
44
|
+
accountPrompt = await deleteSandboxPrompt(config);
|
|
45
|
+
}
|
|
46
|
+
const sandboxAccountId = getAccountId({
|
|
47
|
+
account: account || accountPrompt.account,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
trackCommandUsage('sandbox-delete', {}, sandboxAccountId);
|
|
51
|
+
|
|
52
|
+
let parentAccountId;
|
|
53
|
+
for (const portal of config.portals) {
|
|
54
|
+
if (portal.portalId === sandboxAccountId) {
|
|
55
|
+
if (portal.parentAccountId) {
|
|
56
|
+
parentAccountId = portal.parentAccountId;
|
|
57
|
+
} else {
|
|
58
|
+
const parentAccountPrompt = await deleteSandboxPrompt(config, true);
|
|
59
|
+
parentAccountId = getAccountId({
|
|
60
|
+
account: parentAccountPrompt.account,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!getAccountId({ account: parentAccountId })) {
|
|
67
|
+
const baseUrl = getHubSpotWebsiteOrigin(
|
|
68
|
+
getEnv(sandboxAccountId) === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD
|
|
69
|
+
);
|
|
70
|
+
const url = `${baseUrl}/sandboxes/${parentAccountId}`;
|
|
71
|
+
const command = `hs auth ${
|
|
72
|
+
getEnv(sandboxAccountId) === 'qa' ? '--qa' : ''
|
|
73
|
+
} --account=${parentAccountId}`;
|
|
74
|
+
logger.log('');
|
|
75
|
+
logger.error(
|
|
76
|
+
i18n(`${i18nKey}.noParentPortalAvailable`, {
|
|
77
|
+
parentAccountId,
|
|
78
|
+
url,
|
|
79
|
+
command,
|
|
80
|
+
})
|
|
81
|
+
);
|
|
82
|
+
logger.log('');
|
|
83
|
+
process.exit(EXIT_CODES.ERROR);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
logger.debug(
|
|
87
|
+
i18n(`${i18nKey}.debug.deleting`, {
|
|
88
|
+
account: account || accountPrompt.account,
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
const { confirmSandboxDeletePrompt: confirmed } = await promptUser([
|
|
94
|
+
{
|
|
95
|
+
name: 'confirmSandboxDeletePrompt',
|
|
96
|
+
type: 'confirm',
|
|
97
|
+
message: i18n(`${i18nKey}.confirm`, {
|
|
98
|
+
account: account || accountPrompt.account,
|
|
99
|
+
}),
|
|
100
|
+
},
|
|
101
|
+
]);
|
|
102
|
+
if (!confirmed) {
|
|
103
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
await deleteSandbox(parentAccountId, sandboxAccountId);
|
|
107
|
+
|
|
108
|
+
logger.log('');
|
|
109
|
+
logger.success(
|
|
110
|
+
i18n(`${i18nKey}.success.delete`, {
|
|
111
|
+
account: account || accountPrompt.account,
|
|
112
|
+
sandboxHubId: sandboxAccountId,
|
|
113
|
+
})
|
|
114
|
+
);
|
|
115
|
+
logger.log('');
|
|
116
|
+
|
|
117
|
+
const promptDefaultAccount = removeAccountFromConfig(sandboxAccountId);
|
|
118
|
+
if (promptDefaultAccount) {
|
|
119
|
+
await selectAndSetAsDefaultAccountPrompt(config);
|
|
120
|
+
}
|
|
121
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
122
|
+
} catch (err) {
|
|
123
|
+
debugErrorAndContext(err);
|
|
124
|
+
|
|
125
|
+
if (
|
|
126
|
+
err.error &&
|
|
127
|
+
err.error.category === OBJECT_NOT_FOUND &&
|
|
128
|
+
err.error.subCategory === SANDBOX_NOT_FOUND
|
|
129
|
+
) {
|
|
130
|
+
logger.log('');
|
|
131
|
+
logger.warn(
|
|
132
|
+
i18n(`${i18nKey}.objectNotFound`, {
|
|
133
|
+
account: account || accountPrompt.account,
|
|
134
|
+
})
|
|
135
|
+
);
|
|
136
|
+
logger.log('');
|
|
18
137
|
|
|
19
|
-
|
|
20
|
-
|
|
138
|
+
const promptDefaultAccount = removeAccountFromConfig(sandboxAccountId);
|
|
139
|
+
if (promptDefaultAccount) {
|
|
140
|
+
await selectAndSetAsDefaultAccountPrompt(config);
|
|
141
|
+
}
|
|
142
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
143
|
+
} else {
|
|
144
|
+
logger.error(err.error.message);
|
|
145
|
+
}
|
|
146
|
+
process.exit(EXIT_CODES.ERROR);
|
|
147
|
+
}
|
|
21
148
|
};
|
|
22
149
|
|
|
23
150
|
exports.builder = yargs => {
|
|
@@ -36,6 +163,7 @@ exports.builder = yargs => {
|
|
|
36
163
|
addConfigOptions(yargs, true);
|
|
37
164
|
addAccountOptions(yargs, true);
|
|
38
165
|
addUseEnvironmentOptions(yargs, true);
|
|
166
|
+
addTestingOptions(yargs, true);
|
|
39
167
|
|
|
40
168
|
return yargs;
|
|
41
169
|
};
|
|
@@ -11,13 +11,6 @@ allowUsageTracking: false
|
|
|
11
11
|
|
|
12
12
|
# List of accounts that are intended to be used
|
|
13
13
|
portals:
|
|
14
|
-
# Account set up to use an API Key
|
|
15
|
-
- name: DEV
|
|
16
|
-
portalId: 123
|
|
17
|
-
# Override mode for account
|
|
18
|
-
defaultMode: draft
|
|
19
|
-
authType: apikey
|
|
20
|
-
apiKey: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
|
|
21
14
|
# Account set up to use OAuth2
|
|
22
15
|
- name: PROD
|
|
23
16
|
portalId: 456
|
|
@@ -24,13 +24,6 @@ describe('validation', () => {
|
|
|
24
24
|
getAccountConfig.mockReturnValueOnce(undefined);
|
|
25
25
|
expect(await validateAccount({ account: 123 })).toBe(false);
|
|
26
26
|
});
|
|
27
|
-
it('returns false if an api key is missing', async () => {
|
|
28
|
-
getAccountId.mockReturnValueOnce(123);
|
|
29
|
-
getAccountConfig.mockReturnValueOnce({
|
|
30
|
-
accountId: 123,
|
|
31
|
-
});
|
|
32
|
-
expect(await validateAccount({ account: 123 })).toBe(false);
|
|
33
|
-
});
|
|
34
27
|
it('returns false for oauth2 authType if auth is missing', async () => {
|
|
35
28
|
getAccountId.mockReturnValueOnce(123);
|
|
36
29
|
getAccountConfig.mockReturnValueOnce({
|
package/lib/projects.js
CHANGED
|
@@ -343,8 +343,9 @@ const makePollTaskStatusFunc = ({
|
|
|
343
343
|
}
|
|
344
344
|
};
|
|
345
345
|
|
|
346
|
-
return async (accountId, taskName, taskId) => {
|
|
347
|
-
|
|
346
|
+
return async (accountId, taskName, taskId, deployedBuildId = null) => {
|
|
347
|
+
const displayId = deployedBuildId || taskId;
|
|
348
|
+
|
|
348
349
|
if (linkToHubSpot) {
|
|
349
350
|
logger.log(`\n${linkToHubSpot(taskName, taskId, accountId)}\n`);
|
|
350
351
|
}
|
|
@@ -372,7 +373,7 @@ const makePollTaskStatusFunc = ({
|
|
|
372
373
|
const subTaskName = subTask[statusText.SUBTASK_NAME_KEY];
|
|
373
374
|
|
|
374
375
|
spinnies.add(subTaskName, {
|
|
375
|
-
text: `${chalk.bold(subTaskName)} #${
|
|
376
|
+
text: `${chalk.bold(subTaskName)} #${displayId} ${
|
|
376
377
|
statusText.STATUS_TEXT[statusText.STATES.ENQUEUED]
|
|
377
378
|
}\n`,
|
|
378
379
|
indent: 2,
|
|
@@ -395,7 +396,7 @@ const makePollTaskStatusFunc = ({
|
|
|
395
396
|
return;
|
|
396
397
|
}
|
|
397
398
|
|
|
398
|
-
const updatedText = `${chalk.bold(subTaskName)} #${
|
|
399
|
+
const updatedText = `${chalk.bold(subTaskName)} #${displayId} ${
|
|
399
400
|
statusText.STATUS_TEXT[subTask.status]
|
|
400
401
|
}\n`;
|
|
401
402
|
|
|
@@ -413,17 +414,17 @@ const makePollTaskStatusFunc = ({
|
|
|
413
414
|
});
|
|
414
415
|
|
|
415
416
|
if (isTaskComplete(taskStatus)) {
|
|
416
|
-
subTaskStatus.forEach(subTask => {
|
|
417
|
-
|
|
418
|
-
});
|
|
417
|
+
// subTaskStatus.forEach(subTask => {
|
|
418
|
+
// spinnies.remove(subTask[statusText.SUBTASK_NAME_KEY]);
|
|
419
|
+
// });
|
|
419
420
|
|
|
420
421
|
if (status === statusText.STATES.SUCCESS) {
|
|
421
422
|
spinnies.succeed('overallTaskStatus', {
|
|
422
|
-
text:
|
|
423
|
+
text: statusStrings.SUCCESS(taskName),
|
|
423
424
|
});
|
|
424
425
|
} else if (status === statusText.STATES.FAILURE) {
|
|
425
426
|
spinnies.fail('overallTaskStatus', {
|
|
426
|
-
text:
|
|
427
|
+
text: statusStrings.FAIL(taskName),
|
|
427
428
|
});
|
|
428
429
|
|
|
429
430
|
const failedSubtask = subTaskStatus.filter(
|
|
@@ -433,7 +434,7 @@ const makePollTaskStatusFunc = ({
|
|
|
433
434
|
uiLine();
|
|
434
435
|
logger.log(
|
|
435
436
|
`${statusStrings.SUBTASK_FAIL(
|
|
436
|
-
|
|
437
|
+
displayId,
|
|
437
438
|
failedSubtask.length === 1
|
|
438
439
|
? failedSubtask[0][statusText.SUBTASK_NAME_KEY]
|
|
439
440
|
: failedSubtask.length + ' components'
|
|
@@ -481,8 +482,8 @@ const pollBuildStatus = makePollTaskStatusFunc({
|
|
|
481
482
|
INITIALIZE: name => `Building ${chalk.bold(name)}`,
|
|
482
483
|
SUCCESS: name => `Built ${chalk.bold(name)}`,
|
|
483
484
|
FAIL: name => `Failed to build ${chalk.bold(name)}`,
|
|
484
|
-
SUBTASK_FAIL: (
|
|
485
|
-
`Build #${
|
|
485
|
+
SUBTASK_FAIL: (buildId, name) =>
|
|
486
|
+
`Build #${buildId} failed because there was a problem\nbuilding ${chalk.bold(
|
|
486
487
|
name
|
|
487
488
|
)}`,
|
|
488
489
|
},
|
|
@@ -495,8 +496,8 @@ const pollDeployStatus = makePollTaskStatusFunc({
|
|
|
495
496
|
INITIALIZE: name => `Deploying ${chalk.bold(name)}`,
|
|
496
497
|
SUCCESS: name => `Deployed ${chalk.bold(name)}`,
|
|
497
498
|
FAIL: name => `Failed to deploy ${chalk.bold(name)}`,
|
|
498
|
-
SUBTASK_FAIL: (
|
|
499
|
-
`Deploy for build #${
|
|
499
|
+
SUBTASK_FAIL: (deployedBuildId, name) =>
|
|
500
|
+
`Deploy for build #${deployedBuildId} failed because there was a\nproblem deploying ${chalk.bold(
|
|
500
501
|
name
|
|
501
502
|
)}`,
|
|
502
503
|
},
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const { updateDefaultAccount } = require('@hubspot/cli-lib/lib/config');
|
|
2
|
+
const { promptUser } = require('./promptUtils');
|
|
3
|
+
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
4
|
+
|
|
5
|
+
const i18nKey = 'cli.commands.accounts.subcommands.use';
|
|
6
|
+
|
|
7
|
+
const selectAccountFromConfig = async config => {
|
|
8
|
+
const { default: selectedDefault } = await promptUser([
|
|
9
|
+
{
|
|
10
|
+
type: 'list',
|
|
11
|
+
look: false,
|
|
12
|
+
name: 'default',
|
|
13
|
+
pageSize: 20,
|
|
14
|
+
message: i18n(`${i18nKey}.promptMessage`),
|
|
15
|
+
choices: config.portals.map(p => ({
|
|
16
|
+
name: `${p.name} (${p.portalId})`,
|
|
17
|
+
value: p.name || p.portalId,
|
|
18
|
+
})),
|
|
19
|
+
default: config.defaultPortal,
|
|
20
|
+
},
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
return selectedDefault;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const selectAndSetAsDefaultAccountPrompt = async config => {
|
|
27
|
+
const { default: selectedDefault } = await promptUser([
|
|
28
|
+
{
|
|
29
|
+
type: 'list',
|
|
30
|
+
look: false,
|
|
31
|
+
name: 'default',
|
|
32
|
+
pageSize: 20,
|
|
33
|
+
message: i18n(`${i18nKey}.promptMessage`),
|
|
34
|
+
choices: config.portals.map(p => ({
|
|
35
|
+
name: `${p.name} (${p.portalId})`,
|
|
36
|
+
value: p.name || p.portalId,
|
|
37
|
+
})),
|
|
38
|
+
default: config.defaultPortal,
|
|
39
|
+
},
|
|
40
|
+
]);
|
|
41
|
+
updateDefaultAccount(selectedDefault);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
module.exports = {
|
|
45
|
+
selectAndSetAsDefaultAccountPrompt,
|
|
46
|
+
selectAccountFromConfig,
|
|
47
|
+
};
|
|
@@ -6,7 +6,6 @@ const {
|
|
|
6
6
|
const { deleteEmptyConfigFile } = require('@hubspot/cli-lib/lib/config');
|
|
7
7
|
const { getHubSpotWebsiteOrigin } = require('@hubspot/cli-lib/lib/urls');
|
|
8
8
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
9
|
-
const { API_KEY_REGEX } = require('../regex');
|
|
10
9
|
const { promptUser } = require('./promptUtils');
|
|
11
10
|
const { accountNamePrompt } = require('./enterAccountNamePrompt');
|
|
12
11
|
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
@@ -89,17 +88,6 @@ const CLIENT_SECRET = {
|
|
|
89
88
|
},
|
|
90
89
|
};
|
|
91
90
|
|
|
92
|
-
const ACCOUNT_API_KEY = {
|
|
93
|
-
name: 'apiKey',
|
|
94
|
-
message: i18n(`${i18nKey}.enterApiKey`),
|
|
95
|
-
validate(val) {
|
|
96
|
-
if (!API_KEY_REGEX.test(val)) {
|
|
97
|
-
return i18n(`${i18nKey}.errors.invalidAPIKey`);
|
|
98
|
-
}
|
|
99
|
-
return true;
|
|
100
|
-
},
|
|
101
|
-
};
|
|
102
|
-
|
|
103
91
|
const PERSONAL_ACCESS_KEY_BROWSER_OPEN_PREP = {
|
|
104
92
|
name: 'personalAcessKeyBrowserOpenPrep',
|
|
105
93
|
type: 'confirm',
|
|
@@ -142,17 +130,14 @@ const OAUTH_FLOW = [
|
|
|
142
130
|
CLIENT_SECRET,
|
|
143
131
|
SCOPES,
|
|
144
132
|
];
|
|
145
|
-
const API_KEY_FLOW = [accountNamePrompt(), ACCOUNT_ID, ACCOUNT_API_KEY];
|
|
146
133
|
|
|
147
134
|
module.exports = {
|
|
148
135
|
personalAccessKeyPrompt,
|
|
149
136
|
CLIENT_ID,
|
|
150
137
|
CLIENT_SECRET,
|
|
151
|
-
ACCOUNT_API_KEY,
|
|
152
138
|
ACCOUNT_ID,
|
|
153
139
|
SCOPES,
|
|
154
140
|
PERSONAL_ACCESS_KEY,
|
|
155
141
|
// Flows
|
|
156
|
-
API_KEY_FLOW,
|
|
157
142
|
OAUTH_FLOW,
|
|
158
143
|
};
|
|
@@ -19,6 +19,25 @@ const createSandboxPrompt = () => {
|
|
|
19
19
|
]);
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
+
const deleteSandboxPrompt = (config, promptParentAccount = false) => {
|
|
23
|
+
return promptUser([
|
|
24
|
+
{
|
|
25
|
+
name: 'account',
|
|
26
|
+
message: i18n(
|
|
27
|
+
promptParentAccount
|
|
28
|
+
? `${i18nKey}.selectParentAccountName`
|
|
29
|
+
: `${i18nKey}.selectAccountName`
|
|
30
|
+
),
|
|
31
|
+
type: 'list',
|
|
32
|
+
look: false,
|
|
33
|
+
pageSize: 20,
|
|
34
|
+
choices: config.portals.map(p => p.name || p.portalId),
|
|
35
|
+
default: config.defaultPortal,
|
|
36
|
+
},
|
|
37
|
+
]);
|
|
38
|
+
};
|
|
39
|
+
|
|
22
40
|
module.exports = {
|
|
23
41
|
createSandboxPrompt,
|
|
42
|
+
deleteSandboxPrompt,
|
|
24
43
|
};
|
package/lib/regex.js
CHANGED
package/lib/validation.js
CHANGED
|
@@ -26,14 +26,19 @@ const fs = require('fs');
|
|
|
26
26
|
const path = require('path');
|
|
27
27
|
const { EXIT_CODES } = require('./enums/exitCodes');
|
|
28
28
|
|
|
29
|
-
async function loadAndValidateOptions(options) {
|
|
29
|
+
async function loadAndValidateOptions(options, shouldValidateAccount = true) {
|
|
30
30
|
setLogLevel(options);
|
|
31
31
|
logDebugInfo(options);
|
|
32
32
|
const { config: configPath } = options;
|
|
33
33
|
loadConfig(configPath, options);
|
|
34
34
|
checkAndWarnGitInclusion(getConfigPath());
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
let validAccount = true;
|
|
37
|
+
if (shouldValidateAccount) {
|
|
38
|
+
validAccount = await validateAccount(options);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!(validateConfig() && validAccount)) {
|
|
37
42
|
process.exit(EXIT_CODES.ERROR);
|
|
38
43
|
}
|
|
39
44
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "4.0.1-beta.
|
|
3
|
+
"version": "4.0.1-beta.5",
|
|
4
4
|
"description": "CLI for working with HubSpot",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"url": "https://github.com/HubSpot/hubspot-cms-tools"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@hubspot/cli-lib": "4.0.1-beta.
|
|
12
|
-
"@hubspot/serverless-dev-runtime": "4.0.1-beta.
|
|
11
|
+
"@hubspot/cli-lib": "4.0.1-beta.5",
|
|
12
|
+
"@hubspot/serverless-dev-runtime": "4.0.1-beta.5",
|
|
13
13
|
"archiver": "^5.3.0",
|
|
14
14
|
"chalk": "^4.1.2",
|
|
15
15
|
"express": "^4.17.1",
|
|
@@ -37,5 +37,5 @@
|
|
|
37
37
|
"publishConfig": {
|
|
38
38
|
"access": "public"
|
|
39
39
|
},
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "af927b5e071f91db0dd415fca154a446f259fe3b"
|
|
41
41
|
}
|