@hubspot/cli 3.0.13-beta.4 → 4.0.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 +47 -32
- package/commands/accounts/use.js +8 -5
- package/commands/auth.js +73 -42
- package/commands/config/set.js +4 -1
- package/commands/filemanager/fetch.js +1 -1
- package/commands/init.js +49 -21
- package/commands/project/create.js +12 -5
- package/commands/project/deploy.js +31 -25
- package/commands/project/open.js +5 -1
- package/commands/sandbox/create.js +127 -9
- package/lib/projects.js +9 -28
- package/lib/prompts/enterAccountNamePrompt.js +33 -0
- package/lib/prompts/personalAccessKeyPrompt.js +40 -25
- package/lib/prompts/projectNamePrompt.js +8 -4
- package/lib/prompts/setAsDefaultAccountPrompt.js +30 -0
- package/lib/ui.js +30 -1
- package/package.json +4 -4
package/bin/cli.js
CHANGED
|
@@ -58,24 +58,55 @@ const getTerminalWidth = () => {
|
|
|
58
58
|
return width;
|
|
59
59
|
};
|
|
60
60
|
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
logger.error(msg);
|
|
68
|
-
} else if (err) {
|
|
69
|
-
logErrorInstance(err);
|
|
70
|
-
}
|
|
61
|
+
const handleFailure = (msg, err, yargs) => {
|
|
62
|
+
if (msg) {
|
|
63
|
+
logger.error(msg);
|
|
64
|
+
} else if (err) {
|
|
65
|
+
logErrorInstance(err);
|
|
66
|
+
}
|
|
71
67
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
if (msg === null) {
|
|
69
|
+
yargs.showHelp();
|
|
70
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
71
|
+
} else {
|
|
72
|
+
process.exit(EXIT_CODES.ERROR);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const performChecks = argv => {
|
|
77
|
+
// "hs config set default-account" has moved to "hs accounts use"
|
|
78
|
+
if (
|
|
79
|
+
argv._[0] === 'config' &&
|
|
80
|
+
argv._[1] === 'set' &&
|
|
81
|
+
argv._[2] === 'default-account'
|
|
82
|
+
) {
|
|
83
|
+
logger.error(i18n(`${i18nKey}.setDefaultAccountMoved`));
|
|
84
|
+
process.exit(EXIT_CODES.ERROR);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Require "project" command when running upload/watch inside of a project
|
|
88
|
+
if (argv._.length === 1 && ['upload', 'watch'].includes(argv._[0])) {
|
|
89
|
+
if (getIsInProject(argv.src)) {
|
|
90
|
+
logger.error(
|
|
91
|
+
i18n(`${i18nKey}.srcIsProject`, {
|
|
92
|
+
src: argv.src || './',
|
|
93
|
+
command: argv._.join(' '),
|
|
94
|
+
})
|
|
95
|
+
);
|
|
76
96
|
process.exit(EXIT_CODES.ERROR);
|
|
97
|
+
} else {
|
|
98
|
+
return true;
|
|
77
99
|
}
|
|
78
|
-
}
|
|
100
|
+
} else {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const argv = yargs
|
|
106
|
+
.usage('The command line interface to interact with HubSpot.')
|
|
107
|
+
.middleware([setLogLevel])
|
|
108
|
+
.exitProcess(false)
|
|
109
|
+
.fail(handleFailure)
|
|
79
110
|
.option('debug', {
|
|
80
111
|
alias: 'd',
|
|
81
112
|
default: false,
|
|
@@ -94,23 +125,7 @@ const argv = yargs
|
|
|
94
125
|
hidden: true,
|
|
95
126
|
type: 'boolean',
|
|
96
127
|
})
|
|
97
|
-
.check(
|
|
98
|
-
if (argv._.length === 1 && ['upload', 'watch'].includes(argv._[0])) {
|
|
99
|
-
if (getIsInProject(argv.src)) {
|
|
100
|
-
logger.error(
|
|
101
|
-
i18n(`${i18nKey}.srcIsProject`, {
|
|
102
|
-
src: argv.src,
|
|
103
|
-
command: argv._.join(' '),
|
|
104
|
-
})
|
|
105
|
-
);
|
|
106
|
-
process.exit(EXIT_CODES.ERROR);
|
|
107
|
-
} else {
|
|
108
|
-
return true;
|
|
109
|
-
}
|
|
110
|
-
} else {
|
|
111
|
-
return true;
|
|
112
|
-
}
|
|
113
|
-
})
|
|
128
|
+
.check(performChecks)
|
|
114
129
|
.command(authCommand)
|
|
115
130
|
.command(initCommand)
|
|
116
131
|
.command(logsCommand)
|
package/commands/accounts/use.js
CHANGED
|
@@ -33,7 +33,7 @@ const selectAccountFromConfig = async config => {
|
|
|
33
33
|
return selectedDefault;
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
exports.command = 'use [account]';
|
|
36
|
+
exports.command = 'use [--account]';
|
|
37
37
|
exports.describe = i18n(`${i18nKey}.describe`);
|
|
38
38
|
|
|
39
39
|
exports.handler = async options => {
|
|
@@ -68,14 +68,17 @@ exports.handler = async options => {
|
|
|
68
68
|
};
|
|
69
69
|
|
|
70
70
|
exports.builder = yargs => {
|
|
71
|
-
yargs.
|
|
72
|
-
describe: i18n(`${i18nKey}.
|
|
71
|
+
yargs.option('account', {
|
|
72
|
+
describe: i18n(`${i18nKey}.options.account.describe`),
|
|
73
73
|
type: 'string',
|
|
74
74
|
});
|
|
75
75
|
yargs.example([
|
|
76
76
|
['$0 accounts use', i18n(`${i18nKey}.examples.default`)],
|
|
77
|
-
[
|
|
78
|
-
|
|
77
|
+
[
|
|
78
|
+
'$0 accounts use --account=MyAccount',
|
|
79
|
+
i18n(`${i18nKey}.examples.nameBased`),
|
|
80
|
+
],
|
|
81
|
+
['$0 accounts use --account=1234567', i18n(`${i18nKey}.examples.idBased`)],
|
|
79
82
|
]);
|
|
80
83
|
|
|
81
84
|
return yargs;
|
package/commands/auth.js
CHANGED
|
@@ -13,8 +13,8 @@ const {
|
|
|
13
13
|
} = require('@hubspot/cli-lib/personalAccessKey');
|
|
14
14
|
const {
|
|
15
15
|
updateAccountConfig,
|
|
16
|
-
accountNameExistsInConfig,
|
|
17
16
|
writeConfig,
|
|
17
|
+
getConfig,
|
|
18
18
|
getConfigPath,
|
|
19
19
|
} = require('@hubspot/cli-lib/lib/config');
|
|
20
20
|
const { commaSeparatedValues } = require('@hubspot/cli-lib/lib/text');
|
|
@@ -23,8 +23,13 @@ const {
|
|
|
23
23
|
personalAccessKeyPrompt,
|
|
24
24
|
OAUTH_FLOW,
|
|
25
25
|
API_KEY_FLOW,
|
|
26
|
-
ACCOUNT_NAME,
|
|
27
26
|
} = require('../lib/prompts/personalAccessKeyPrompt');
|
|
27
|
+
const {
|
|
28
|
+
enterAccountNamePrompt,
|
|
29
|
+
} = require('../lib/prompts/enterAccountNamePrompt');
|
|
30
|
+
const {
|
|
31
|
+
setAsDefaultAccountPrompt,
|
|
32
|
+
} = require('../lib/prompts/setAsDefaultAccountPrompt');
|
|
28
33
|
const {
|
|
29
34
|
addConfigOptions,
|
|
30
35
|
setLogLevel,
|
|
@@ -34,6 +39,7 @@ const { logDebugInfo } = require('../lib/debugInfo');
|
|
|
34
39
|
const { trackCommandUsage } = require('../lib/usageTracking');
|
|
35
40
|
const { authenticateWithOauth } = require('../lib/oauth');
|
|
36
41
|
const { EXIT_CODES } = require('../lib/enums/exitCodes');
|
|
42
|
+
const { uiFeatureHighlight } = require('../lib/ui');
|
|
37
43
|
|
|
38
44
|
const i18nKey = 'cli.commands.auth';
|
|
39
45
|
|
|
@@ -45,34 +51,13 @@ const SUPPORTED_AUTHENTICATION_PROTOCOLS_TEXT = commaSeparatedValues(
|
|
|
45
51
|
ALLOWED_AUTH_METHODS
|
|
46
52
|
);
|
|
47
53
|
|
|
48
|
-
|
|
49
|
-
if (!updatedConfig.name) {
|
|
50
|
-
let promptAnswer;
|
|
51
|
-
let validName = null;
|
|
52
|
-
while (!validName) {
|
|
53
|
-
promptAnswer = await promptUser([ACCOUNT_NAME]);
|
|
54
|
-
|
|
55
|
-
if (!accountNameExistsInConfig(promptAnswer.name)) {
|
|
56
|
-
validName = promptAnswer.name;
|
|
57
|
-
} else {
|
|
58
|
-
logger.log(
|
|
59
|
-
i18n(`${i18nKey}.errors.accountNameExists`, {
|
|
60
|
-
name: promptAnswer.name,
|
|
61
|
-
})
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return validName;
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
exports.command = 'auth [type]';
|
|
54
|
+
exports.command = 'auth [type] [--account]';
|
|
70
55
|
exports.describe = i18n(`${i18nKey}.describe`, {
|
|
71
56
|
supportedProtocols: SUPPORTED_AUTHENTICATION_PROTOCOLS_TEXT,
|
|
72
57
|
});
|
|
73
58
|
|
|
74
59
|
exports.handler = async options => {
|
|
75
|
-
const { type, config: configPath, qa } = options;
|
|
60
|
+
const { type, config: configPath, qa, account } = options;
|
|
76
61
|
const authType =
|
|
77
62
|
(type && type.toLowerCase()) || PERSONAL_ACCESS_KEY_AUTH_METHOD.value;
|
|
78
63
|
setLogLevel(options);
|
|
@@ -92,11 +77,18 @@ exports.handler = async options => {
|
|
|
92
77
|
let configData;
|
|
93
78
|
let updatedConfig;
|
|
94
79
|
let validName;
|
|
80
|
+
let successAuthMethod;
|
|
81
|
+
|
|
95
82
|
switch (authType) {
|
|
96
83
|
case API_KEY_AUTH_METHOD.value:
|
|
97
84
|
configData = await promptUser(API_KEY_FLOW);
|
|
98
85
|
updatedConfig = await updateAccountConfig(configData);
|
|
99
|
-
validName =
|
|
86
|
+
validName = updatedConfig.name;
|
|
87
|
+
|
|
88
|
+
if (!validName) {
|
|
89
|
+
const { name: namePrompt } = await enterAccountNamePrompt();
|
|
90
|
+
validName = namePrompt;
|
|
91
|
+
}
|
|
100
92
|
|
|
101
93
|
updateAccountConfig({
|
|
102
94
|
...updatedConfig,
|
|
@@ -105,13 +97,7 @@ exports.handler = async options => {
|
|
|
105
97
|
});
|
|
106
98
|
writeConfig();
|
|
107
99
|
|
|
108
|
-
|
|
109
|
-
i18n(`${i18nKey}.success.configFileUpdated`, {
|
|
110
|
-
configFilename: DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME,
|
|
111
|
-
authMethod: API_KEY_AUTH_METHOD.name,
|
|
112
|
-
})
|
|
113
|
-
);
|
|
114
|
-
|
|
100
|
+
successAuthMethod = API_KEY_AUTH_METHOD.name;
|
|
115
101
|
break;
|
|
116
102
|
case OAUTH_AUTH_METHOD.value:
|
|
117
103
|
configData = await promptUser(OAUTH_FLOW);
|
|
@@ -119,16 +105,22 @@ exports.handler = async options => {
|
|
|
119
105
|
...configData,
|
|
120
106
|
env,
|
|
121
107
|
});
|
|
108
|
+
successAuthMethod = OAUTH_AUTH_METHOD.name;
|
|
122
109
|
break;
|
|
123
110
|
case PERSONAL_ACCESS_KEY_AUTH_METHOD.value:
|
|
124
|
-
configData = await personalAccessKeyPrompt({ env });
|
|
111
|
+
configData = await personalAccessKeyPrompt({ env, account });
|
|
125
112
|
updatedConfig = await updateConfigWithPersonalAccessKey(configData);
|
|
126
113
|
|
|
127
114
|
if (!updatedConfig) {
|
|
128
|
-
|
|
115
|
+
break;
|
|
129
116
|
}
|
|
130
117
|
|
|
131
|
-
validName =
|
|
118
|
+
validName = updatedConfig.name;
|
|
119
|
+
|
|
120
|
+
if (!validName) {
|
|
121
|
+
const { name: namePrompt } = await enterAccountNamePrompt();
|
|
122
|
+
validName = namePrompt;
|
|
123
|
+
}
|
|
132
124
|
|
|
133
125
|
updateAccountConfig({
|
|
134
126
|
...updatedConfig,
|
|
@@ -138,12 +130,7 @@ exports.handler = async options => {
|
|
|
138
130
|
});
|
|
139
131
|
writeConfig();
|
|
140
132
|
|
|
141
|
-
|
|
142
|
-
i18n(`${i18nKey}.success.configFileUpdated`, {
|
|
143
|
-
configFilename: DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME,
|
|
144
|
-
authMethod: PERSONAL_ACCESS_KEY_AUTH_METHOD.name,
|
|
145
|
-
})
|
|
146
|
-
);
|
|
133
|
+
successAuthMethod = PERSONAL_ACCESS_KEY_AUTH_METHOD.name;
|
|
147
134
|
break;
|
|
148
135
|
default:
|
|
149
136
|
logger.error(
|
|
@@ -154,6 +141,43 @@ exports.handler = async options => {
|
|
|
154
141
|
);
|
|
155
142
|
break;
|
|
156
143
|
}
|
|
144
|
+
|
|
145
|
+
if (!successAuthMethod) {
|
|
146
|
+
process.exit(EXIT_CODES.ERROR);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const accountName = updatedConfig.name || validName;
|
|
150
|
+
|
|
151
|
+
const setAsDefault = await setAsDefaultAccountPrompt(accountName);
|
|
152
|
+
|
|
153
|
+
logger.log('');
|
|
154
|
+
if (setAsDefault) {
|
|
155
|
+
logger.success(
|
|
156
|
+
i18n(`cli.lib.prompts.setAsDefaultAccountPrompt.setAsDefaultAccount`, {
|
|
157
|
+
accountName,
|
|
158
|
+
})
|
|
159
|
+
);
|
|
160
|
+
} else {
|
|
161
|
+
const config = getConfig();
|
|
162
|
+
logger.info(
|
|
163
|
+
i18n(`cli.lib.prompts.setAsDefaultAccountPrompt.keepingCurrentDefault`, {
|
|
164
|
+
accountName: config.defaultPortal,
|
|
165
|
+
})
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
logger.success(
|
|
169
|
+
i18n(`${i18nKey}.success.configFileUpdated`, {
|
|
170
|
+
configFilename: DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME,
|
|
171
|
+
authType: successAuthMethod,
|
|
172
|
+
accountName,
|
|
173
|
+
})
|
|
174
|
+
);
|
|
175
|
+
uiFeatureHighlight([
|
|
176
|
+
'accountsUseCommand',
|
|
177
|
+
'accountOption',
|
|
178
|
+
'accountsListCommand',
|
|
179
|
+
]);
|
|
180
|
+
|
|
157
181
|
process.exit(EXIT_CODES.SUCCESS);
|
|
158
182
|
};
|
|
159
183
|
|
|
@@ -172,6 +196,13 @@ exports.builder = yargs => {
|
|
|
172
196
|
}),
|
|
173
197
|
});
|
|
174
198
|
|
|
199
|
+
yargs.options({
|
|
200
|
+
account: {
|
|
201
|
+
describe: i18n(`${i18nKey}.options.account.describe`),
|
|
202
|
+
type: 'string',
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
|
|
175
206
|
addConfigOptions(yargs, true);
|
|
176
207
|
addTestingOptions(yargs, true);
|
|
177
208
|
|
package/commands/config/set.js
CHANGED
|
@@ -33,7 +33,7 @@ const selectOptions = async () => {
|
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
const handleConfigUpdate = async (accountId, options) => {
|
|
36
|
-
const { defaultMode, httpTimeout
|
|
36
|
+
const { allowUsageTracking, defaultMode, httpTimeout } = options;
|
|
37
37
|
|
|
38
38
|
if (typeof defaultMode !== 'undefined') {
|
|
39
39
|
await setDefaultMode({ defaultMode, accountId });
|
|
@@ -89,5 +89,8 @@ exports.builder = yargs => {
|
|
|
89
89
|
|
|
90
90
|
yargs.example([['$0 config set', i18n(`${i18nKey}.examples.default`)]]);
|
|
91
91
|
|
|
92
|
+
//TODO remove this when "hs accounts use" is fully rolled out
|
|
93
|
+
yargs.strict(false);
|
|
94
|
+
|
|
92
95
|
return yargs;
|
|
93
96
|
};
|
|
@@ -35,7 +35,7 @@ exports.handler = async options => {
|
|
|
35
35
|
trackCommandUsage('filemanager-fetch', {}, accountId);
|
|
36
36
|
|
|
37
37
|
// Fetch and write file/folder.
|
|
38
|
-
downloadFileOrFolder(accountId, src, dest, options);
|
|
38
|
+
await downloadFileOrFolder(accountId, src, dest, options);
|
|
39
39
|
};
|
|
40
40
|
|
|
41
41
|
exports.builder = yargs => {
|
package/commands/init.js
CHANGED
|
@@ -30,12 +30,15 @@ const { promptUser } = require('../lib/prompts/promptUtils');
|
|
|
30
30
|
const {
|
|
31
31
|
OAUTH_FLOW,
|
|
32
32
|
API_KEY_FLOW,
|
|
33
|
-
ACCOUNT_NAME,
|
|
34
33
|
personalAccessKeyPrompt,
|
|
35
34
|
} = require('../lib/prompts/personalAccessKeyPrompt');
|
|
35
|
+
const {
|
|
36
|
+
enterAccountNamePrompt,
|
|
37
|
+
} = require('../lib/prompts/enterAccountNamePrompt');
|
|
36
38
|
const { logDebugInfo } = require('../lib/debugInfo');
|
|
37
39
|
const { authenticateWithOauth } = require('../lib/oauth');
|
|
38
40
|
const { EXIT_CODES } = require('../lib/enums/exitCodes');
|
|
41
|
+
const { uiFeatureHighlight } = require('../lib/ui');
|
|
39
42
|
|
|
40
43
|
const i18nKey = 'cli.commands.init';
|
|
41
44
|
|
|
@@ -45,9 +48,9 @@ const TRACKING_STATUS = {
|
|
|
45
48
|
COMPLETE: 'complete',
|
|
46
49
|
};
|
|
47
50
|
|
|
48
|
-
const personalAccessKeyConfigCreationFlow = async env => {
|
|
49
|
-
const configData = await personalAccessKeyPrompt({ env });
|
|
50
|
-
const { name } = await
|
|
51
|
+
const personalAccessKeyConfigCreationFlow = async (env, account) => {
|
|
52
|
+
const configData = await personalAccessKeyPrompt({ env, account });
|
|
53
|
+
const { name } = await enterAccountNamePrompt();
|
|
51
54
|
const accountConfig = {
|
|
52
55
|
...configData,
|
|
53
56
|
name,
|
|
@@ -85,13 +88,23 @@ const CONFIG_CREATION_FLOWS = {
|
|
|
85
88
|
[API_KEY_AUTH_METHOD.value]: apiKeyConfigCreationFlow,
|
|
86
89
|
};
|
|
87
90
|
|
|
88
|
-
|
|
91
|
+
const AUTH_TYPE_NAMES = {
|
|
92
|
+
[PERSONAL_ACCESS_KEY_AUTH_METHOD.value]: PERSONAL_ACCESS_KEY_AUTH_METHOD.name,
|
|
93
|
+
[OAUTH_AUTH_METHOD.value]: OAUTH_AUTH_METHOD.name,
|
|
94
|
+
[API_KEY_AUTH_METHOD.value]: API_KEY_AUTH_METHOD.name,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
exports.command = 'init [--account]';
|
|
89
98
|
exports.describe = i18n(`${i18nKey}.describe`, {
|
|
90
99
|
configName: DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME,
|
|
91
100
|
});
|
|
92
101
|
|
|
93
102
|
exports.handler = async options => {
|
|
94
|
-
const {
|
|
103
|
+
const {
|
|
104
|
+
auth: authType = PERSONAL_ACCESS_KEY_AUTH_METHOD.value,
|
|
105
|
+
c,
|
|
106
|
+
account: optionalAccount,
|
|
107
|
+
} = options;
|
|
95
108
|
const configPath = (c && path.join(getCwd(), c)) || getConfigPath();
|
|
96
109
|
setLogLevel(options);
|
|
97
110
|
logDebugInfo(options);
|
|
@@ -106,7 +119,7 @@ exports.handler = async options => {
|
|
|
106
119
|
configPath,
|
|
107
120
|
})
|
|
108
121
|
);
|
|
109
|
-
logger.info(i18n(`${i18nKey}.
|
|
122
|
+
logger.info(i18n(`${i18nKey}.logs.updateConfig`));
|
|
110
123
|
process.exit(EXIT_CODES.ERROR);
|
|
111
124
|
}
|
|
112
125
|
|
|
@@ -115,16 +128,25 @@ exports.handler = async options => {
|
|
|
115
128
|
handleExit(deleteEmptyConfigFile);
|
|
116
129
|
|
|
117
130
|
try {
|
|
118
|
-
const { accountId, name } = await CONFIG_CREATION_FLOWS[authType](
|
|
131
|
+
const { accountId, name } = await CONFIG_CREATION_FLOWS[authType](
|
|
132
|
+
env,
|
|
133
|
+
optionalAccount
|
|
134
|
+
);
|
|
119
135
|
const configPath = getConfigPath();
|
|
120
136
|
|
|
137
|
+
logger.log('');
|
|
121
138
|
logger.success(
|
|
122
139
|
i18n(`${i18nKey}.success.configFileCreated`, {
|
|
123
140
|
configPath,
|
|
124
|
-
|
|
141
|
+
})
|
|
142
|
+
);
|
|
143
|
+
logger.success(
|
|
144
|
+
i18n(`${i18nKey}.success.configFileUpdated`, {
|
|
145
|
+
authType: AUTH_TYPE_NAMES[authType],
|
|
125
146
|
account: name || accountId,
|
|
126
147
|
})
|
|
127
148
|
);
|
|
149
|
+
uiFeatureHighlight(['helpCommand', 'authCommand', 'accountsListCommand']);
|
|
128
150
|
|
|
129
151
|
trackAuthAction('init', authType, TRACKING_STATUS.COMPLETE, accountId);
|
|
130
152
|
process.exit(EXIT_CODES.SUCCESS);
|
|
@@ -135,18 +157,24 @@ exports.handler = async options => {
|
|
|
135
157
|
};
|
|
136
158
|
|
|
137
159
|
exports.builder = yargs => {
|
|
138
|
-
yargs.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
160
|
+
yargs.options({
|
|
161
|
+
auth: {
|
|
162
|
+
describe: i18n(`${i18nKey}.options.auth.describe`),
|
|
163
|
+
type: 'string',
|
|
164
|
+
choices: [
|
|
165
|
+
`${PERSONAL_ACCESS_KEY_AUTH_METHOD.value}`,
|
|
166
|
+
`${OAUTH_AUTH_METHOD.value}`,
|
|
167
|
+
`${API_KEY_AUTH_METHOD.value}`,
|
|
168
|
+
],
|
|
169
|
+
default: PERSONAL_ACCESS_KEY_AUTH_METHOD.value,
|
|
170
|
+
defaultDescription: i18n(`${i18nKey}.options.auth.defaultDescription`, {
|
|
171
|
+
defaultType: PERSONAL_ACCESS_KEY_AUTH_METHOD.value,
|
|
172
|
+
}),
|
|
173
|
+
},
|
|
174
|
+
account: {
|
|
175
|
+
describe: i18n(`${i18nKey}.options.account.describe`),
|
|
176
|
+
type: 'string',
|
|
177
|
+
},
|
|
150
178
|
});
|
|
151
179
|
|
|
152
180
|
addConfigOptions(yargs, true);
|
|
@@ -8,14 +8,14 @@ const { trackCommandUsage } = require('../../lib/usageTracking');
|
|
|
8
8
|
const { loadAndValidateOptions } = require('../../lib/validation');
|
|
9
9
|
const { getCwd } = require('@hubspot/cli-lib/path');
|
|
10
10
|
const path = require('path');
|
|
11
|
+
const chalk = require('chalk');
|
|
11
12
|
const {
|
|
12
13
|
createProjectPrompt,
|
|
13
14
|
} = require('../../lib/prompts/createProjectPrompt');
|
|
14
|
-
const {
|
|
15
|
-
createProjectConfig,
|
|
16
|
-
showProjectWelcomeMessage,
|
|
17
|
-
} = require('../../lib/projects');
|
|
15
|
+
const { createProjectConfig } = require('../../lib/projects');
|
|
18
16
|
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
17
|
+
const { uiFeatureHighlight } = require('../../lib/ui');
|
|
18
|
+
const { logger } = require('@hubspot/cli-lib/logger');
|
|
19
19
|
|
|
20
20
|
const i18nKey = 'cli.commands.project.subcommands.create';
|
|
21
21
|
|
|
@@ -37,7 +37,14 @@ exports.handler = async options => {
|
|
|
37
37
|
options.template || template
|
|
38
38
|
);
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
logger.log('');
|
|
41
|
+
logger.log(chalk.bold(i18n(`${i18nKey}.logs.welcomeMessage`)));
|
|
42
|
+
uiFeatureHighlight([
|
|
43
|
+
'createCommand',
|
|
44
|
+
'projectUploadCommand',
|
|
45
|
+
'projectDeployCommand',
|
|
46
|
+
'projectHelpCommand',
|
|
47
|
+
]);
|
|
41
48
|
};
|
|
42
49
|
|
|
43
50
|
exports.builder = yargs => {
|
|
@@ -12,41 +12,44 @@ const {
|
|
|
12
12
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
13
13
|
const { deployProject, fetchProject } = require('@hubspot/cli-lib/api/dfs');
|
|
14
14
|
const { loadAndValidateOptions } = require('../../lib/validation');
|
|
15
|
-
const {
|
|
16
|
-
|
|
17
|
-
pollDeployStatus,
|
|
18
|
-
validateProjectConfig,
|
|
19
|
-
} = require('../../lib/projects');
|
|
15
|
+
const { getProjectConfig, pollDeployStatus } = require('../../lib/projects');
|
|
16
|
+
const { projectNamePrompt } = require('../../lib/prompts/projectNamePrompt');
|
|
20
17
|
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
21
18
|
|
|
22
19
|
const i18nKey = 'cli.commands.project.subcommands.deploy';
|
|
23
20
|
const { EXIT_CODES } = require('../../lib/enums/exitCodes');
|
|
24
21
|
|
|
25
|
-
exports.command = 'deploy [
|
|
22
|
+
exports.command = 'deploy [--project] [--buildId]';
|
|
26
23
|
exports.describe = i18n(`${i18nKey}.describe`);
|
|
27
24
|
|
|
28
25
|
exports.handler = async options => {
|
|
29
26
|
await loadAndValidateOptions(options);
|
|
30
27
|
|
|
31
|
-
const { path: projectPath, buildId } = options;
|
|
32
28
|
const accountId = getAccountId(options);
|
|
29
|
+
const { project, buildId } = options;
|
|
33
30
|
|
|
34
|
-
trackCommandUsage('project-deploy', {
|
|
31
|
+
trackCommandUsage('project-deploy', { project }, accountId);
|
|
35
32
|
|
|
36
|
-
const { projectConfig
|
|
33
|
+
const { projectConfig } = await getProjectConfig();
|
|
37
34
|
|
|
38
|
-
|
|
35
|
+
let projectName = project;
|
|
39
36
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
if (!projectName && projectConfig) {
|
|
38
|
+
projectName = projectConfig.name;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const namePrompt = await projectNamePrompt(accountId, {
|
|
42
|
+
project: projectName,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (!projectName && namePrompt.projectName) {
|
|
46
|
+
projectName = namePrompt.projectName;
|
|
47
|
+
}
|
|
45
48
|
|
|
46
49
|
let exitCode = EXIT_CODES.SUCCESS;
|
|
47
50
|
|
|
48
51
|
const getBuildId = async () => {
|
|
49
|
-
const { latestBuild } = await fetchProject(accountId,
|
|
52
|
+
const { latestBuild } = await fetchProject(accountId, projectName);
|
|
50
53
|
if (latestBuild && latestBuild.buildId) {
|
|
51
54
|
return latestBuild.buildId;
|
|
52
55
|
}
|
|
@@ -60,7 +63,7 @@ exports.handler = async options => {
|
|
|
60
63
|
|
|
61
64
|
const deployResp = await deployProject(
|
|
62
65
|
accountId,
|
|
63
|
-
|
|
66
|
+
projectName,
|
|
64
67
|
deployedBuildId
|
|
65
68
|
);
|
|
66
69
|
|
|
@@ -76,7 +79,7 @@ exports.handler = async options => {
|
|
|
76
79
|
|
|
77
80
|
await pollDeployStatus(
|
|
78
81
|
accountId,
|
|
79
|
-
|
|
82
|
+
projectName,
|
|
80
83
|
deployResp.id,
|
|
81
84
|
deployedBuildId
|
|
82
85
|
);
|
|
@@ -84,7 +87,7 @@ exports.handler = async options => {
|
|
|
84
87
|
if (e.statusCode === 400) {
|
|
85
88
|
logger.error(e.error.message);
|
|
86
89
|
} else {
|
|
87
|
-
logApiErrorInstance(e, new ApiErrorContext({ accountId,
|
|
90
|
+
logApiErrorInstance(e, new ApiErrorContext({ accountId, projectName }));
|
|
88
91
|
}
|
|
89
92
|
exitCode = 1;
|
|
90
93
|
}
|
|
@@ -92,20 +95,23 @@ exports.handler = async options => {
|
|
|
92
95
|
};
|
|
93
96
|
|
|
94
97
|
exports.builder = yargs => {
|
|
95
|
-
yargs.positional('path', {
|
|
96
|
-
describe: i18n(`${i18nKey}.positionals.path.describe`),
|
|
97
|
-
type: 'string',
|
|
98
|
-
});
|
|
99
|
-
|
|
100
98
|
yargs.options({
|
|
99
|
+
project: {
|
|
100
|
+
describe: i18n(`${i18nKey}.options.project.describe`),
|
|
101
|
+
type: 'string',
|
|
102
|
+
},
|
|
101
103
|
buildId: {
|
|
102
104
|
describe: i18n(`${i18nKey}.options.buildId.describe`),
|
|
103
105
|
type: 'number',
|
|
104
106
|
},
|
|
105
107
|
});
|
|
106
108
|
|
|
109
|
+
yargs.example([['$0 project deploy', i18n(`${i18nKey}.examples.default`)]]);
|
|
107
110
|
yargs.example([
|
|
108
|
-
[
|
|
111
|
+
[
|
|
112
|
+
'$0 project deploy --project="my-project" --buildId=5',
|
|
113
|
+
i18n(`${i18nKey}.examples.withOptions`),
|
|
114
|
+
],
|
|
109
115
|
]);
|
|
110
116
|
|
|
111
117
|
addConfigOptions(yargs, true);
|
package/commands/project/open.js
CHANGED
|
@@ -6,6 +6,7 @@ const {
|
|
|
6
6
|
addUseEnvironmentOptions,
|
|
7
7
|
addTestingOptions,
|
|
8
8
|
} = require('../../lib/commonOpts');
|
|
9
|
+
const { trackCommandUsage } = require('../../lib/usageTracking');
|
|
9
10
|
const { loadAndValidateOptions } = require('../../lib/validation');
|
|
10
11
|
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
11
12
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
@@ -27,6 +28,9 @@ exports.handler = async options => {
|
|
|
27
28
|
|
|
28
29
|
const accountId = getAccountId(options);
|
|
29
30
|
const { project } = options;
|
|
31
|
+
|
|
32
|
+
trackCommandUsage('project-open', { project }, accountId);
|
|
33
|
+
|
|
30
34
|
const { projectConfig } = await getProjectConfig();
|
|
31
35
|
|
|
32
36
|
let projectName = project;
|
|
@@ -42,7 +46,7 @@ exports.handler = async options => {
|
|
|
42
46
|
} else if (!projectName && projectConfig) {
|
|
43
47
|
projectName = projectConfig.name;
|
|
44
48
|
} else if (!projectName && !projectConfig) {
|
|
45
|
-
const namePrompt = await projectNamePrompt(accountId
|
|
49
|
+
const namePrompt = await projectNamePrompt(accountId);
|
|
46
50
|
|
|
47
51
|
if (!namePrompt.projectName) {
|
|
48
52
|
process.exit(EXIT_CODES.ERROR);
|
|
@@ -3,6 +3,7 @@ const {
|
|
|
3
3
|
addConfigOptions,
|
|
4
4
|
getAccountId,
|
|
5
5
|
addUseEnvironmentOptions,
|
|
6
|
+
addTestingOptions,
|
|
6
7
|
} = require('../../lib/commonOpts');
|
|
7
8
|
const { trackCommandUsage } = require('../../lib/usageTracking');
|
|
8
9
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
@@ -11,9 +12,97 @@ const { createSandbox } = require('@hubspot/cli-lib/sandboxes');
|
|
|
11
12
|
const { loadAndValidateOptions } = require('../../lib/validation');
|
|
12
13
|
const { createSandboxPrompt } = require('../../lib/prompts/sandboxesPrompt');
|
|
13
14
|
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
15
|
+
const { logErrorInstance } = require('@hubspot/cli-lib/errorHandlers');
|
|
16
|
+
const {
|
|
17
|
+
ENVIRONMENTS,
|
|
18
|
+
PERSONAL_ACCESS_KEY_AUTH_METHOD,
|
|
19
|
+
DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME,
|
|
20
|
+
} = require('@hubspot/cli-lib/lib/constants');
|
|
21
|
+
const {
|
|
22
|
+
personalAccessKeyPrompt,
|
|
23
|
+
} = require('../../lib/prompts/personalAccessKeyPrompt');
|
|
24
|
+
const {
|
|
25
|
+
updateConfigWithPersonalAccessKey,
|
|
26
|
+
} = require('@hubspot/cli-lib/personalAccessKey');
|
|
27
|
+
const { EXIT_CODES } = require('../../lib/enums/exitCodes');
|
|
28
|
+
const {
|
|
29
|
+
getConfig,
|
|
30
|
+
writeConfig,
|
|
31
|
+
updateAccountConfig,
|
|
32
|
+
getAccountConfig,
|
|
33
|
+
} = require('@hubspot/cli-lib');
|
|
34
|
+
const {
|
|
35
|
+
enterAccountNamePrompt,
|
|
36
|
+
} = require('../../lib/prompts/enterAccountNamePrompt');
|
|
37
|
+
const {
|
|
38
|
+
setAsDefaultAccountPrompt,
|
|
39
|
+
} = require('../../lib/prompts/setAsDefaultAccountPrompt');
|
|
40
|
+
const { getHubSpotWebsiteOrigin } = require('@hubspot/cli-lib/lib/urls');
|
|
41
|
+
const {
|
|
42
|
+
isMissingScopeError,
|
|
43
|
+
} = require('@hubspot/cli-lib/errorHandlers/apiErrors');
|
|
44
|
+
const { uiFeatureHighlight } = require('../../lib/ui');
|
|
14
45
|
|
|
15
46
|
const i18nKey = 'cli.commands.sandbox.subcommands.create';
|
|
16
47
|
|
|
48
|
+
const personalAccessKeyFlow = async (env, account, name) => {
|
|
49
|
+
const configData = await personalAccessKeyPrompt({ env, account });
|
|
50
|
+
const updatedConfig = await updateConfigWithPersonalAccessKey(configData);
|
|
51
|
+
|
|
52
|
+
if (!updatedConfig) {
|
|
53
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let validName = updatedConfig.name;
|
|
57
|
+
|
|
58
|
+
if (!updatedConfig.name) {
|
|
59
|
+
const nameForConfig = name
|
|
60
|
+
.toLowerCase()
|
|
61
|
+
.split(' ')
|
|
62
|
+
.join('-');
|
|
63
|
+
const { name: promptName } = await enterAccountNamePrompt(nameForConfig);
|
|
64
|
+
validName = promptName;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
updateAccountConfig({
|
|
68
|
+
...updatedConfig,
|
|
69
|
+
environment: updatedConfig.env,
|
|
70
|
+
tokenInfo: updatedConfig.auth.tokenInfo,
|
|
71
|
+
name: validName,
|
|
72
|
+
});
|
|
73
|
+
writeConfig();
|
|
74
|
+
|
|
75
|
+
const setAsDefault = await setAsDefaultAccountPrompt(validName);
|
|
76
|
+
|
|
77
|
+
logger.log('');
|
|
78
|
+
if (setAsDefault) {
|
|
79
|
+
logger.success(
|
|
80
|
+
i18n(`cli.lib.prompts.setAsDefaultAccountPrompt.setAsDefaultAccount`, {
|
|
81
|
+
accountName: validName,
|
|
82
|
+
})
|
|
83
|
+
);
|
|
84
|
+
} else {
|
|
85
|
+
const config = getConfig();
|
|
86
|
+
logger.info(
|
|
87
|
+
i18n(`cli.lib.prompts.setAsDefaultAccountPrompt.keepingCurrentDefault`, {
|
|
88
|
+
accountName: config.defaultPortal,
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
logger.success(
|
|
93
|
+
i18n(`${i18nKey}.success.configFileUpdated`, {
|
|
94
|
+
configFilename: DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME,
|
|
95
|
+
authMethod: PERSONAL_ACCESS_KEY_AUTH_METHOD.name,
|
|
96
|
+
account: validName,
|
|
97
|
+
})
|
|
98
|
+
);
|
|
99
|
+
uiFeatureHighlight([
|
|
100
|
+
'accountsUseCommand',
|
|
101
|
+
'accountOption',
|
|
102
|
+
'accountsListCommand',
|
|
103
|
+
]);
|
|
104
|
+
};
|
|
105
|
+
|
|
17
106
|
exports.command = 'create [name]';
|
|
18
107
|
exports.describe = i18n(`${i18nKey}.describe`);
|
|
19
108
|
|
|
@@ -22,6 +111,8 @@ exports.handler = async options => {
|
|
|
22
111
|
|
|
23
112
|
const { name } = options;
|
|
24
113
|
const accountId = getAccountId(options);
|
|
114
|
+
const accountConfig = getAccountConfig(accountId);
|
|
115
|
+
const env = options.qa ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD;
|
|
25
116
|
let namePrompt;
|
|
26
117
|
|
|
27
118
|
trackCommandUsage('sandbox-create', {}, accountId);
|
|
@@ -37,18 +128,44 @@ exports.handler = async options => {
|
|
|
37
128
|
name: sandboxName,
|
|
38
129
|
})
|
|
39
130
|
);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
131
|
+
let result;
|
|
132
|
+
try {
|
|
133
|
+
result = await createSandbox(accountId, sandboxName).then(
|
|
134
|
+
({ name, sandboxHubId }) => {
|
|
135
|
+
logger.log('');
|
|
136
|
+
logger.success(
|
|
137
|
+
i18n(`${i18nKey}.success.create`, {
|
|
138
|
+
name,
|
|
139
|
+
sandboxHubId,
|
|
140
|
+
})
|
|
141
|
+
);
|
|
142
|
+
return { name, sandboxHubId };
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
} catch (err) {
|
|
146
|
+
if (isMissingScopeError(err)) {
|
|
147
|
+
logger.error(
|
|
148
|
+
i18n(`${i18nKey}.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(`${i18nKey}.failure.scopes.instructions`, {
|
|
156
|
+
accountName: accountConfig.name || accountId,
|
|
157
|
+
url,
|
|
47
158
|
})
|
|
48
159
|
);
|
|
49
|
-
logger.info(i18n(`${i18nKey}.info.auth`));
|
|
50
160
|
}
|
|
51
|
-
|
|
161
|
+
process.exit(EXIT_CODES.ERROR);
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
await personalAccessKeyFlow(env, result.sandboxHubId, result.name);
|
|
165
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
166
|
+
} catch (err) {
|
|
167
|
+
logErrorInstance(err);
|
|
168
|
+
}
|
|
52
169
|
};
|
|
53
170
|
|
|
54
171
|
exports.builder = yargs => {
|
|
@@ -64,6 +181,7 @@ exports.builder = yargs => {
|
|
|
64
181
|
addConfigOptions(yargs, true);
|
|
65
182
|
addAccountOptions(yargs, true);
|
|
66
183
|
addUseEnvironmentOptions(yargs, true);
|
|
184
|
+
addTestingOptions(yargs, true);
|
|
67
185
|
|
|
68
186
|
return yargs;
|
|
69
187
|
};
|
package/lib/projects.js
CHANGED
|
@@ -165,7 +165,7 @@ const validateProjectConfig = (projectConfig, projectDir) => {
|
|
|
165
165
|
const ensureProjectExists = async (
|
|
166
166
|
accountId,
|
|
167
167
|
projectName,
|
|
168
|
-
{ forceCreate = false, allowCreate = true } = {}
|
|
168
|
+
{ forceCreate = false, allowCreate = true, noLogs = false } = {}
|
|
169
169
|
) => {
|
|
170
170
|
try {
|
|
171
171
|
const project = await fetchProject(accountId, projectName);
|
|
@@ -194,11 +194,13 @@ const ensureProjectExists = async (
|
|
|
194
194
|
return logApiErrorInstance(err, new ApiErrorContext({ accountId }));
|
|
195
195
|
}
|
|
196
196
|
} else {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
197
|
+
if (!noLogs) {
|
|
198
|
+
logger.log(
|
|
199
|
+
`Your project ${chalk.bold(
|
|
200
|
+
projectName
|
|
201
|
+
)} could not be found in ${chalk.bold(accountId)}.`
|
|
202
|
+
);
|
|
203
|
+
}
|
|
202
204
|
return false;
|
|
203
205
|
}
|
|
204
206
|
}
|
|
@@ -211,7 +213,7 @@ const getProjectDetailUrl = (projectName, accountId) => {
|
|
|
211
213
|
if (!projectName) return;
|
|
212
214
|
|
|
213
215
|
const baseUrl = getHubSpotWebsiteOrigin(
|
|
214
|
-
getEnv() === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD
|
|
216
|
+
getEnv(accountId) === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD
|
|
215
217
|
);
|
|
216
218
|
|
|
217
219
|
return `${baseUrl}/developer-projects/${accountId}/project/${projectName}`;
|
|
@@ -324,26 +326,6 @@ const handleProjectUpload = async (
|
|
|
324
326
|
archive.finalize();
|
|
325
327
|
};
|
|
326
328
|
|
|
327
|
-
const showProjectWelcomeMessage = () => {
|
|
328
|
-
logger.log('');
|
|
329
|
-
logger.log(chalk.bold('Welcome to HubSpot Developer Projects!'));
|
|
330
|
-
logger.log('\n');
|
|
331
|
-
uiLine();
|
|
332
|
-
logger.log('\n');
|
|
333
|
-
logger.log(chalk.bold("What's next?\n"));
|
|
334
|
-
logger.log('🎨 Add components to your project with `hs create`.\n');
|
|
335
|
-
logger.log(
|
|
336
|
-
`🏗 Run \`hs project upload\` to upload your files to HubSpot and trigger builds.\n`
|
|
337
|
-
);
|
|
338
|
-
logger.log(
|
|
339
|
-
`🚀 Ready to take your project live? Run \`hs project deploy\`.\n`
|
|
340
|
-
);
|
|
341
|
-
logger.log(
|
|
342
|
-
`🔗 Use \`hs project --help\` to learn more about available commands.\n`
|
|
343
|
-
);
|
|
344
|
-
uiLine();
|
|
345
|
-
};
|
|
346
|
-
|
|
347
329
|
const makePollTaskStatusFunc = ({
|
|
348
330
|
statusFn,
|
|
349
331
|
statusText,
|
|
@@ -519,7 +501,6 @@ module.exports = {
|
|
|
519
501
|
handleProjectUpload,
|
|
520
502
|
createProjectConfig,
|
|
521
503
|
validateProjectConfig,
|
|
522
|
-
showProjectWelcomeMessage,
|
|
523
504
|
getProjectDetailUrl,
|
|
524
505
|
getProjectBuildDetailUrl,
|
|
525
506
|
pollBuildStatus,
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const { accountNameExistsInConfig } = require('@hubspot/cli-lib/lib/config');
|
|
2
|
+
const { STRING_WITH_NO_SPACES_REGEX } = require('../regex');
|
|
3
|
+
const { promptUser } = require('./promptUtils');
|
|
4
|
+
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
5
|
+
|
|
6
|
+
const i18nKey = 'cli.lib.prompts.enterAccountNamePrompt';
|
|
7
|
+
|
|
8
|
+
const accountNamePrompt = defaultName => ({
|
|
9
|
+
name: 'name',
|
|
10
|
+
message: i18n(`${i18nKey}.enterAccountName`),
|
|
11
|
+
default: defaultName,
|
|
12
|
+
validate(val) {
|
|
13
|
+
if (typeof val !== 'string') {
|
|
14
|
+
return i18n(`${i18nKey}.errors.invalidName`);
|
|
15
|
+
} else if (!val.length) {
|
|
16
|
+
return i18n(`${i18nKey}.errors.nameRequired`);
|
|
17
|
+
} else if (!STRING_WITH_NO_SPACES_REGEX.test(val)) {
|
|
18
|
+
return i18n(`${i18nKey}.errors.spacesInName`);
|
|
19
|
+
}
|
|
20
|
+
return accountNameExistsInConfig(val)
|
|
21
|
+
? i18n(`${i18nKey}.errors.accountNameExists`, { name: val })
|
|
22
|
+
: true;
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const enterAccountNamePrompt = defaultName => {
|
|
27
|
+
return promptUser(accountNamePrompt(defaultName));
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
module.exports = {
|
|
31
|
+
accountNamePrompt,
|
|
32
|
+
enterAccountNamePrompt,
|
|
33
|
+
};
|
|
@@ -3,11 +3,15 @@ const {
|
|
|
3
3
|
OAUTH_SCOPES,
|
|
4
4
|
DEFAULT_OAUTH_SCOPES,
|
|
5
5
|
} = require('@hubspot/cli-lib/lib/constants');
|
|
6
|
+
const { deleteEmptyConfigFile } = require('@hubspot/cli-lib/lib/config');
|
|
6
7
|
const { getHubSpotWebsiteOrigin } = require('@hubspot/cli-lib/lib/urls');
|
|
7
8
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
8
|
-
const { API_KEY_REGEX
|
|
9
|
+
const { API_KEY_REGEX } = require('../regex');
|
|
9
10
|
const { promptUser } = require('./promptUtils');
|
|
11
|
+
const { accountNamePrompt } = require('./enterAccountNamePrompt');
|
|
10
12
|
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
13
|
+
const { uiInfoSection } = require('../ui');
|
|
14
|
+
const { EXIT_CODES } = require('../enums/exitCodes');
|
|
11
15
|
|
|
12
16
|
const i18nKey = 'cli.lib.prompts.personalAccessKeyPrompt';
|
|
13
17
|
|
|
@@ -15,12 +19,25 @@ const i18nKey = 'cli.lib.prompts.personalAccessKeyPrompt';
|
|
|
15
19
|
* Displays notification to user that we are about to open the browser,
|
|
16
20
|
* then opens their browser to the personal-access-key shortlink
|
|
17
21
|
*/
|
|
18
|
-
const personalAccessKeyPrompt = async ({ env } = {}) => {
|
|
22
|
+
const personalAccessKeyPrompt = async ({ env, account } = {}) => {
|
|
19
23
|
const websiteOrigin = getHubSpotWebsiteOrigin(env);
|
|
20
|
-
|
|
24
|
+
let url = `${websiteOrigin}/l/personal-access-key`;
|
|
21
25
|
if (process.env.BROWSER !== 'none') {
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
uiInfoSection(i18n(`${i18nKey}.personalAccessKeySetupTitle`), () => {
|
|
27
|
+
logger.log(i18n(`${i18nKey}.personalAccessKeyBrowserOpenPrep`));
|
|
28
|
+
});
|
|
29
|
+
if (account) {
|
|
30
|
+
url = `${websiteOrigin}/personal-access-key/${account}`;
|
|
31
|
+
}
|
|
32
|
+
const { personalAcessKeyBrowserOpenPrep: shouldOpen } = await promptUser([
|
|
33
|
+
PERSONAL_ACCESS_KEY_BROWSER_OPEN_PREP,
|
|
34
|
+
]);
|
|
35
|
+
if (shouldOpen) {
|
|
36
|
+
open(url, { url: true });
|
|
37
|
+
} else {
|
|
38
|
+
deleteEmptyConfigFile();
|
|
39
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
40
|
+
}
|
|
24
41
|
}
|
|
25
42
|
|
|
26
43
|
logger.log(i18n(`${i18nKey}.logs.openingWebBrowser`, { url }));
|
|
@@ -72,21 +89,6 @@ const CLIENT_SECRET = {
|
|
|
72
89
|
},
|
|
73
90
|
};
|
|
74
91
|
|
|
75
|
-
const ACCOUNT_NAME = {
|
|
76
|
-
name: 'name',
|
|
77
|
-
message: i18n(`${i18nKey}.enterAccountName`),
|
|
78
|
-
validate(val) {
|
|
79
|
-
if (typeof val !== 'string') {
|
|
80
|
-
return i18n(`${i18nKey}.errors.invalidName`);
|
|
81
|
-
} else if (!val.length) {
|
|
82
|
-
return i18n(`${i18nKey}.errors.nameRequired`);
|
|
83
|
-
} else if (!STRING_WITH_NO_SPACES_REGEX.test(val)) {
|
|
84
|
-
return i18n(`${i18nKey}.errors.spacesInName`);
|
|
85
|
-
}
|
|
86
|
-
return true;
|
|
87
|
-
},
|
|
88
|
-
};
|
|
89
|
-
|
|
90
92
|
const ACCOUNT_API_KEY = {
|
|
91
93
|
name: 'apiKey',
|
|
92
94
|
message: i18n(`${i18nKey}.enterApiKey`),
|
|
@@ -100,12 +102,21 @@ const ACCOUNT_API_KEY = {
|
|
|
100
102
|
|
|
101
103
|
const PERSONAL_ACCESS_KEY_BROWSER_OPEN_PREP = {
|
|
102
104
|
name: 'personalAcessKeyBrowserOpenPrep',
|
|
103
|
-
|
|
105
|
+
type: 'confirm',
|
|
106
|
+
message: i18n(`${i18nKey}.personalAccessKeyBrowserOpenPrompt`),
|
|
104
107
|
};
|
|
105
108
|
|
|
106
109
|
const PERSONAL_ACCESS_KEY = {
|
|
107
110
|
name: 'personalAccessKey',
|
|
108
111
|
message: i18n(`${i18nKey}.enterPersonalAccessKey`),
|
|
112
|
+
transformer: val => {
|
|
113
|
+
if (!val) return val;
|
|
114
|
+
let res = '';
|
|
115
|
+
for (let i = 0; i < val.length; i++) {
|
|
116
|
+
res += '*';
|
|
117
|
+
}
|
|
118
|
+
return res;
|
|
119
|
+
},
|
|
109
120
|
validate(val) {
|
|
110
121
|
if (!val || typeof val !== 'string') {
|
|
111
122
|
return i18n(`${i18nKey}.errors.invalidPersonalAccessKey`);
|
|
@@ -124,8 +135,14 @@ const SCOPES = {
|
|
|
124
135
|
choices: OAUTH_SCOPES,
|
|
125
136
|
};
|
|
126
137
|
|
|
127
|
-
const OAUTH_FLOW = [
|
|
128
|
-
|
|
138
|
+
const OAUTH_FLOW = [
|
|
139
|
+
accountNamePrompt(),
|
|
140
|
+
ACCOUNT_ID,
|
|
141
|
+
CLIENT_ID,
|
|
142
|
+
CLIENT_SECRET,
|
|
143
|
+
SCOPES,
|
|
144
|
+
];
|
|
145
|
+
const API_KEY_FLOW = [accountNamePrompt(), ACCOUNT_ID, ACCOUNT_API_KEY];
|
|
129
146
|
|
|
130
147
|
module.exports = {
|
|
131
148
|
personalAccessKeyPrompt,
|
|
@@ -133,10 +150,8 @@ module.exports = {
|
|
|
133
150
|
CLIENT_SECRET,
|
|
134
151
|
ACCOUNT_API_KEY,
|
|
135
152
|
ACCOUNT_ID,
|
|
136
|
-
ACCOUNT_NAME,
|
|
137
153
|
SCOPES,
|
|
138
154
|
PERSONAL_ACCESS_KEY,
|
|
139
|
-
|
|
140
155
|
// Flows
|
|
141
156
|
API_KEY_FLOW,
|
|
142
157
|
OAUTH_FLOW,
|
|
@@ -4,20 +4,24 @@ const { ensureProjectExists } = require('../projects');
|
|
|
4
4
|
|
|
5
5
|
const i18nKey = 'cli.lib.prompts.projectNamePrompt';
|
|
6
6
|
|
|
7
|
-
const projectNamePrompt = accountId => {
|
|
7
|
+
const projectNamePrompt = (accountId, options = {}) => {
|
|
8
8
|
return promptUser({
|
|
9
9
|
name: 'projectName',
|
|
10
10
|
message: i18n(`${i18nKey}.enterName`),
|
|
11
|
+
when: !options.project,
|
|
11
12
|
validate: async val => {
|
|
12
|
-
if (typeof val !== 'string') {
|
|
13
|
+
if (typeof val !== 'string' || !val) {
|
|
13
14
|
return i18n(`${i18nKey}.errors.invalidName`);
|
|
14
15
|
}
|
|
15
16
|
const projectExists = await ensureProjectExists(accountId, val, {
|
|
16
17
|
allowCreate: false,
|
|
18
|
+
noLogs: true,
|
|
17
19
|
});
|
|
18
|
-
|
|
19
20
|
if (!projectExists) {
|
|
20
|
-
return
|
|
21
|
+
return i18n(`${i18nKey}.errors.projectDoesNotExist`, {
|
|
22
|
+
projectName: val,
|
|
23
|
+
accountId,
|
|
24
|
+
});
|
|
21
25
|
}
|
|
22
26
|
return true;
|
|
23
27
|
},
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const {
|
|
2
|
+
getConfig,
|
|
3
|
+
updateDefaultAccount,
|
|
4
|
+
} = require('@hubspot/cli-lib/lib/config');
|
|
5
|
+
const { promptUser } = require('./promptUtils');
|
|
6
|
+
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
7
|
+
|
|
8
|
+
const i18nKey = 'cli.lib.prompts.setAsDefaultAccountPrompt';
|
|
9
|
+
|
|
10
|
+
const setAsDefaultAccountPrompt = async accountName => {
|
|
11
|
+
const config = getConfig();
|
|
12
|
+
|
|
13
|
+
const { setAsDefault } = await promptUser([
|
|
14
|
+
{
|
|
15
|
+
name: 'setAsDefault',
|
|
16
|
+
type: 'confirm',
|
|
17
|
+
when: config.defaultPortal !== accountName,
|
|
18
|
+
message: i18n(`${i18nKey}.setAsDefaultAccountMessage`),
|
|
19
|
+
},
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
if (setAsDefault) {
|
|
23
|
+
updateDefaultAccount(accountName);
|
|
24
|
+
}
|
|
25
|
+
return setAsDefault;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
module.exports = {
|
|
29
|
+
setAsDefaultAccountPrompt,
|
|
30
|
+
};
|
package/lib/ui.js
CHANGED
|
@@ -2,6 +2,7 @@ const chalk = require('chalk');
|
|
|
2
2
|
const supportsHyperlinks = require('../lib/supportHyperlinks');
|
|
3
3
|
const supportsColor = require('../lib/supportsColor');
|
|
4
4
|
const { getAccountConfig } = require('@hubspot/cli-lib/lib/config');
|
|
5
|
+
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
5
6
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -65,8 +66,36 @@ const uiAccountDescription = accountId => {
|
|
|
65
66
|
);
|
|
66
67
|
};
|
|
67
68
|
|
|
69
|
+
const uiInfoSection = (title, logContent) => {
|
|
70
|
+
uiLine();
|
|
71
|
+
logger.log(chalk.bold(title));
|
|
72
|
+
logger.log('');
|
|
73
|
+
logContent();
|
|
74
|
+
logger.log('');
|
|
75
|
+
uiLine();
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const uiFeatureHighlight = (commands, title) => {
|
|
79
|
+
const i18nKey = 'cli.lib.ui.featureHighlight';
|
|
80
|
+
|
|
81
|
+
uiInfoSection(title ? title : i18n(`${i18nKey}.defaultTitle`), () => {
|
|
82
|
+
commands.forEach((c, i) => {
|
|
83
|
+
const commandKey = `${i18nKey}.commandKeys.${c}`;
|
|
84
|
+
const message = i18n(`${commandKey}.message`, {
|
|
85
|
+
command: chalk.bold(i18n(`${commandKey}.command`)),
|
|
86
|
+
});
|
|
87
|
+
if (i !== 0) {
|
|
88
|
+
logger.log('');
|
|
89
|
+
}
|
|
90
|
+
logger.log(message);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
|
|
68
95
|
module.exports = {
|
|
96
|
+
uiAccountDescription,
|
|
97
|
+
uiFeatureHighlight,
|
|
98
|
+
uiInfoSection,
|
|
69
99
|
uiLine,
|
|
70
100
|
uiLink,
|
|
71
|
-
uiAccountDescription,
|
|
72
101
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.1-beta.1",
|
|
4
4
|
"description": "CLI for working with HubSpot",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"url": "https://github.com/HubSpot/hubspot-cms-tools"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@hubspot/cli-lib": "
|
|
12
|
-
"@hubspot/serverless-dev-runtime": "
|
|
11
|
+
"@hubspot/cli-lib": "4.0.1-beta.1",
|
|
12
|
+
"@hubspot/serverless-dev-runtime": "4.0.1-beta.1",
|
|
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": "eb69a779b705cb7cd43f2c2930fb09f2121283b1"
|
|
41
41
|
}
|