@hubspot/cli 3.0.13-beta.2 → 4.0.0
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 +57 -30
- package/commands/accounts/use.js +8 -5
- package/commands/config/set.js +4 -1
- package/commands/project/logs.js +26 -15
- package/commands/upload.js +8 -3
- package/commands/watch.js +8 -2
- package/lib/hasFlag.js +15 -0
- package/lib/projects.js +2 -3
- package/lib/prompts/projectsLogsPrompt.js +54 -3
- package/lib/prompts/uploadPrompt.js +39 -0
- package/lib/serverlessLogs.js +7 -1
- package/lib/supportHyperlinks.js +75 -0
- package/lib/supportsColor.js +129 -0
- package/lib/ui.js +22 -5
- package/package.json +4 -5
package/bin/cli.js
CHANGED
|
@@ -58,47 +58,74 @@ const getTerminalWidth = () => {
|
|
|
58
58
|
return width;
|
|
59
59
|
};
|
|
60
60
|
|
|
61
|
+
const handleFailure = (msg, err, yargs) => {
|
|
62
|
+
if (msg) {
|
|
63
|
+
logger.error(msg);
|
|
64
|
+
} else if (err) {
|
|
65
|
+
logErrorInstance(err);
|
|
66
|
+
}
|
|
67
|
+
|
|
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
|
+
);
|
|
96
|
+
process.exit(EXIT_CODES.ERROR);
|
|
97
|
+
} else {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
61
105
|
const argv = yargs
|
|
62
106
|
.usage('Tools for working with HubSpot')
|
|
63
107
|
.middleware([setLogLevel])
|
|
64
108
|
.exitProcess(false)
|
|
65
|
-
.fail(
|
|
66
|
-
if (msg) {
|
|
67
|
-
logger.error(msg);
|
|
68
|
-
} else if (err) {
|
|
69
|
-
logErrorInstance(err);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (msg === null) {
|
|
73
|
-
yargs.showHelp();
|
|
74
|
-
process.exit(EXIT_CODES.SUCCESS);
|
|
75
|
-
} else {
|
|
76
|
-
process.exit(EXIT_CODES.ERROR);
|
|
77
|
-
}
|
|
78
|
-
})
|
|
109
|
+
.fail(handleFailure)
|
|
79
110
|
.option('debug', {
|
|
80
111
|
alias: 'd',
|
|
81
112
|
default: false,
|
|
82
113
|
describe: 'set log level to debug',
|
|
83
114
|
type: 'boolean',
|
|
84
115
|
})
|
|
85
|
-
.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return true;
|
|
97
|
-
}
|
|
98
|
-
} else {
|
|
99
|
-
return true;
|
|
100
|
-
}
|
|
116
|
+
.option('noHyperlinks', {
|
|
117
|
+
default: false,
|
|
118
|
+
describe: 'prevent hyperlinks from displaying in the ui',
|
|
119
|
+
hidden: true,
|
|
120
|
+
type: 'boolean',
|
|
121
|
+
})
|
|
122
|
+
.option('noColor', {
|
|
123
|
+
default: false,
|
|
124
|
+
describe: 'prevent color from displaying in the ui',
|
|
125
|
+
hidden: true,
|
|
126
|
+
type: 'boolean',
|
|
101
127
|
})
|
|
128
|
+
.check(performChecks)
|
|
102
129
|
.command(authCommand)
|
|
103
130
|
.command(initCommand)
|
|
104
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/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
|
};
|
package/commands/project/logs.js
CHANGED
|
@@ -120,7 +120,7 @@ const handleFunctionLog = async (accountId, options) => {
|
|
|
120
120
|
return false;
|
|
121
121
|
};
|
|
122
122
|
|
|
123
|
-
exports.command = 'logs [--project] [--app] [--function]';
|
|
123
|
+
exports.command = 'logs [--project] [--app] [--function] [--endpoint]';
|
|
124
124
|
exports.describe = i18n(`${i18nKey}.describe`);
|
|
125
125
|
|
|
126
126
|
exports.handler = async options => {
|
|
@@ -128,21 +128,22 @@ exports.handler = async options => {
|
|
|
128
128
|
|
|
129
129
|
const accountId = getAccountId(options);
|
|
130
130
|
|
|
131
|
-
logger.log(options);
|
|
132
131
|
const {
|
|
133
132
|
projectName: promptProjectName,
|
|
134
133
|
appName: promptAppName,
|
|
135
134
|
functionName: promptFunctionName,
|
|
135
|
+
endpointName: promptEndpointName,
|
|
136
136
|
} = await projectLogsPrompt(accountId, options);
|
|
137
137
|
|
|
138
138
|
const projectName = options.project || promptProjectName;
|
|
139
139
|
const appName = options.app || promptAppName;
|
|
140
140
|
const functionName =
|
|
141
141
|
options.function || promptFunctionName || options.endpoint;
|
|
142
|
+
const endpointName = options.endpoint || promptEndpointName;
|
|
142
143
|
|
|
143
144
|
let relativeAppPath;
|
|
144
145
|
|
|
145
|
-
if (appName && !
|
|
146
|
+
if (appName && !endpointName) {
|
|
146
147
|
await ensureProjectExists(accountId, projectName, {
|
|
147
148
|
allowCreate: false,
|
|
148
149
|
});
|
|
@@ -168,21 +169,31 @@ exports.handler = async options => {
|
|
|
168
169
|
|
|
169
170
|
trackCommandUsage('project-logs', { latest: options.latest }, accountId);
|
|
170
171
|
|
|
171
|
-
const logsInfo = [
|
|
172
|
-
|
|
173
|
-
];
|
|
172
|
+
const logsInfo = [accountId, `"${projectName}"`];
|
|
173
|
+
let tableHeader;
|
|
174
174
|
|
|
175
|
-
|
|
176
|
-
|
|
175
|
+
if (endpointName) {
|
|
176
|
+
logsInfo.push(`"${endpointName}"`);
|
|
177
|
+
tableHeader = getTableHeader([
|
|
178
|
+
i18n(`${i18nKey}.table.accountHeader`),
|
|
179
|
+
i18n(`${i18nKey}.table.projectHeader`),
|
|
180
|
+
i18n(`${i18nKey}.table.endpointHeader`),
|
|
181
|
+
]);
|
|
182
|
+
} else {
|
|
183
|
+
logsInfo.push(`"${appName}"`);
|
|
184
|
+
logsInfo.push(functionName);
|
|
185
|
+
tableHeader = getTableHeader([
|
|
177
186
|
i18n(`${i18nKey}.table.accountHeader`),
|
|
178
187
|
i18n(`${i18nKey}.table.projectHeader`),
|
|
179
188
|
i18n(`${i18nKey}.table.appHeader`),
|
|
180
189
|
i18n(`${i18nKey}.table.functionHeader`),
|
|
181
|
-
])
|
|
182
|
-
|
|
190
|
+
]);
|
|
191
|
+
}
|
|
183
192
|
|
|
184
193
|
logger.log(i18n(`${i18nKey}.logs.showingLogs`));
|
|
185
|
-
logger.log(
|
|
194
|
+
logger.log(
|
|
195
|
+
getTableContents([tableHeader, logsInfo], { border: { bodyLeft: ' ' } })
|
|
196
|
+
);
|
|
186
197
|
|
|
187
198
|
logger.log(
|
|
188
199
|
uiLink(
|
|
@@ -197,7 +208,7 @@ exports.handler = async options => {
|
|
|
197
208
|
...options,
|
|
198
209
|
projectName,
|
|
199
210
|
appPath: relativeAppPath,
|
|
200
|
-
functionName,
|
|
211
|
+
functionName: functionName || endpointName,
|
|
201
212
|
});
|
|
202
213
|
|
|
203
214
|
if (showFinalMessage) {
|
|
@@ -217,7 +228,6 @@ exports.builder = yargs => {
|
|
|
217
228
|
endpoint: {
|
|
218
229
|
alias: 'endpoint',
|
|
219
230
|
describe: i18n(`${i18nKey}.options.endpoint.describe`),
|
|
220
|
-
hidden: true,
|
|
221
231
|
requiresArg: true,
|
|
222
232
|
type: 'string',
|
|
223
233
|
},
|
|
@@ -253,10 +263,11 @@ exports.builder = yargs => {
|
|
|
253
263
|
})
|
|
254
264
|
.conflicts('follow', 'limit');
|
|
255
265
|
|
|
266
|
+
yargs.example([['$0 project logs', i18n(`${i18nKey}.examples.default`)]]);
|
|
256
267
|
yargs.example([
|
|
257
268
|
[
|
|
258
|
-
'$0 project logs --project=
|
|
259
|
-
i18n(`${i18nKey}.examples.
|
|
269
|
+
'$0 project logs --project=my-project --app=app --function=my-function',
|
|
270
|
+
i18n(`${i18nKey}.examples.withOptions`),
|
|
260
271
|
],
|
|
261
272
|
]);
|
|
262
273
|
|
package/commands/upload.js
CHANGED
|
@@ -26,6 +26,7 @@ const {
|
|
|
26
26
|
getAccountId,
|
|
27
27
|
getMode,
|
|
28
28
|
} = require('../lib/commonOpts');
|
|
29
|
+
const { uploadPrompt } = require('../lib/prompts/uploadPrompt');
|
|
29
30
|
const { validateMode, loadAndValidateOptions } = require('../lib/validation');
|
|
30
31
|
const { trackCommandUsage } = require('../lib/usageTracking');
|
|
31
32
|
const { getThemePreviewUrl } = require('@hubspot/cli-lib/lib/files');
|
|
@@ -34,7 +35,7 @@ const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
|
34
35
|
const i18nKey = 'cli.commands.upload';
|
|
35
36
|
const { EXIT_CODES } = require('../lib/enums/exitCodes');
|
|
36
37
|
|
|
37
|
-
exports.command = 'upload
|
|
38
|
+
exports.command = 'upload [--src] [--dest]';
|
|
38
39
|
exports.describe = i18n(`${i18nKey}.describe`);
|
|
39
40
|
|
|
40
41
|
const logThemePreview = (filePath, accountId) => {
|
|
@@ -50,8 +51,6 @@ const logThemePreview = (filePath, accountId) => {
|
|
|
50
51
|
};
|
|
51
52
|
|
|
52
53
|
exports.handler = async options => {
|
|
53
|
-
const { src, dest } = options;
|
|
54
|
-
|
|
55
54
|
await loadAndValidateOptions(options);
|
|
56
55
|
|
|
57
56
|
if (!validateMode(options)) {
|
|
@@ -60,6 +59,12 @@ exports.handler = async options => {
|
|
|
60
59
|
|
|
61
60
|
const accountId = getAccountId(options);
|
|
62
61
|
const mode = getMode(options);
|
|
62
|
+
|
|
63
|
+
const uploadPromptAnswers = await uploadPrompt(options);
|
|
64
|
+
|
|
65
|
+
const src = options.src || uploadPromptAnswers.src;
|
|
66
|
+
const dest = options.dest || uploadPromptAnswers.dest;
|
|
67
|
+
|
|
63
68
|
const absoluteSrcPath = path.resolve(getCwd(), src);
|
|
64
69
|
let stats;
|
|
65
70
|
try {
|
package/commands/watch.js
CHANGED
|
@@ -13,6 +13,7 @@ const {
|
|
|
13
13
|
getAccountId,
|
|
14
14
|
getMode,
|
|
15
15
|
} = require('../lib/commonOpts');
|
|
16
|
+
const { uploadPrompt } = require('../lib/prompts/uploadPrompt');
|
|
16
17
|
const { validateMode, loadAndValidateOptions } = require('../lib/validation');
|
|
17
18
|
const { trackCommandUsage } = require('../lib/usageTracking');
|
|
18
19
|
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
@@ -20,11 +21,11 @@ const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
|
20
21
|
const i18nKey = 'cli.commands.watch';
|
|
21
22
|
const { EXIT_CODES } = require('../lib/enums/exitCodes');
|
|
22
23
|
|
|
23
|
-
exports.command = 'watch
|
|
24
|
+
exports.command = 'watch [--src] [--dest]';
|
|
24
25
|
exports.describe = i18n(`${i18nKey}.describe`);
|
|
25
26
|
|
|
26
27
|
exports.handler = async options => {
|
|
27
|
-
const {
|
|
28
|
+
const { remove, initialUpload, disableInitial, notify } = options;
|
|
28
29
|
|
|
29
30
|
await loadAndValidateOptions(options);
|
|
30
31
|
|
|
@@ -35,6 +36,11 @@ exports.handler = async options => {
|
|
|
35
36
|
const accountId = getAccountId(options);
|
|
36
37
|
const mode = getMode(options);
|
|
37
38
|
|
|
39
|
+
const uploadPromptAnswers = await uploadPrompt(options);
|
|
40
|
+
|
|
41
|
+
const src = options.src || uploadPromptAnswers.src;
|
|
42
|
+
const dest = options.dest || uploadPromptAnswers.dest;
|
|
43
|
+
|
|
38
44
|
const absoluteSrcPath = path.resolve(getCwd(), src);
|
|
39
45
|
try {
|
|
40
46
|
const stats = fs.statSync(absoluteSrcPath);
|
package/lib/hasFlag.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const process = require('process');
|
|
2
|
+
|
|
3
|
+
// See https://github.com/sindresorhus/has-flag/blob/main/index.js (License: https://github.com/sindresorhus/has-flag/blob/main/license)
|
|
4
|
+
|
|
5
|
+
function hasFlag(flag, argv = process.argv) {
|
|
6
|
+
const prefix = flag.startsWith('-') ? '' : flag.length === 1 ? '-' : '--';
|
|
7
|
+
const position = argv.indexOf(prefix + flag);
|
|
8
|
+
const terminatorPosition = argv.indexOf('--');
|
|
9
|
+
return (
|
|
10
|
+
position !== -1 &&
|
|
11
|
+
(terminatorPosition === -1 || position < terminatorPosition)
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = hasFlag;
|
package/lib/projects.js
CHANGED
|
@@ -211,7 +211,7 @@ const getProjectDetailUrl = (projectName, accountId) => {
|
|
|
211
211
|
if (!projectName) return;
|
|
212
212
|
|
|
213
213
|
const baseUrl = getHubSpotWebsiteOrigin(
|
|
214
|
-
getEnv() === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD
|
|
214
|
+
getEnv(accountId) === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD
|
|
215
215
|
);
|
|
216
216
|
|
|
217
217
|
return `${baseUrl}/developer-projects/${accountId}/project/${projectName}`;
|
|
@@ -483,8 +483,7 @@ const pollBuildStatus = makePollTaskStatusFunc({
|
|
|
483
483
|
linkToHubSpot: (projectName, buildId, accountId) =>
|
|
484
484
|
uiLink(
|
|
485
485
|
`View build #${buildId} in HubSpot`,
|
|
486
|
-
getProjectBuildDetailUrl(projectName, buildId, accountId)
|
|
487
|
-
{ useColor: true }
|
|
486
|
+
getProjectBuildDetailUrl(projectName, buildId, accountId)
|
|
488
487
|
),
|
|
489
488
|
statusFn: getBuildStatus,
|
|
490
489
|
statusText: PROJECT_BUILD_TEXT,
|
|
@@ -7,22 +7,55 @@ const { EXIT_CODES } = require('../enums/exitCodes');
|
|
|
7
7
|
|
|
8
8
|
const i18nKey = 'cli.lib.prompts.projectLogsPrompt';
|
|
9
9
|
|
|
10
|
+
const SERVERLESS_FUNCTION_TYPES = {
|
|
11
|
+
APP_FUNCTION: 'app-function',
|
|
12
|
+
PUBLIC_ENDPOINT: 'public-endpoint',
|
|
13
|
+
};
|
|
14
|
+
|
|
10
15
|
const projectLogsPrompt = (accountId, promptOptions = {}) => {
|
|
11
16
|
return promptUser([
|
|
12
17
|
{
|
|
13
18
|
name: 'projectName',
|
|
14
|
-
message: i18n(`${i18nKey}.projectName`),
|
|
19
|
+
message: i18n(`${i18nKey}.projectName.message`),
|
|
15
20
|
when: !promptOptions.project,
|
|
16
21
|
default: async () => {
|
|
17
22
|
const { projectConfig } = await getProjectConfig();
|
|
18
23
|
return projectConfig && projectConfig.name ? projectConfig.name : null;
|
|
19
24
|
},
|
|
25
|
+
validate: name =>
|
|
26
|
+
!name.length ? i18n(`${i18nKey}.projectName.error`) : true,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'logType',
|
|
30
|
+
type: 'list',
|
|
31
|
+
message: i18n(`${i18nKey}.logType.message`),
|
|
32
|
+
when:
|
|
33
|
+
!promptOptions.app &&
|
|
34
|
+
!promptOptions.function &&
|
|
35
|
+
!promptOptions.endpoint,
|
|
36
|
+
choices: [
|
|
37
|
+
{
|
|
38
|
+
name: i18n(`${i18nKey}.logType.function`),
|
|
39
|
+
value: SERVERLESS_FUNCTION_TYPES.APP_FUNCTION,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: i18n(`${i18nKey}.logType.endpoint`),
|
|
43
|
+
value: SERVERLESS_FUNCTION_TYPES.PUBLIC_ENDPOINT,
|
|
44
|
+
},
|
|
45
|
+
],
|
|
20
46
|
},
|
|
21
47
|
{
|
|
22
48
|
name: 'appName',
|
|
23
49
|
type: 'list',
|
|
24
50
|
message: i18n(`${i18nKey}.appName`),
|
|
25
|
-
when:
|
|
51
|
+
when: ({ logType }) => {
|
|
52
|
+
return (
|
|
53
|
+
(promptOptions.function ||
|
|
54
|
+
logType === SERVERLESS_FUNCTION_TYPES.APP_FUNCTION) &&
|
|
55
|
+
!promptOptions.app &&
|
|
56
|
+
!promptOptions.endpoint
|
|
57
|
+
);
|
|
58
|
+
},
|
|
26
59
|
choices: async ({ projectName }) => {
|
|
27
60
|
const name = projectName || promptOptions.project;
|
|
28
61
|
|
|
@@ -47,7 +80,25 @@ const projectLogsPrompt = (accountId, promptOptions = {}) => {
|
|
|
47
80
|
{
|
|
48
81
|
name: 'functionName',
|
|
49
82
|
message: i18n(`${i18nKey}.functionName`),
|
|
50
|
-
when:
|
|
83
|
+
when: ({ logType }) => {
|
|
84
|
+
return (
|
|
85
|
+
(promptOptions.app ||
|
|
86
|
+
logType === SERVERLESS_FUNCTION_TYPES.APP_FUNCTION) &&
|
|
87
|
+
!promptOptions.function &&
|
|
88
|
+
!promptOptions.endpoint
|
|
89
|
+
);
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: 'endpointName',
|
|
94
|
+
message: i18n(`${i18nKey}.endpointName`),
|
|
95
|
+
when: ({ logType }) => {
|
|
96
|
+
return (
|
|
97
|
+
logType === SERVERLESS_FUNCTION_TYPES.PUBLIC_ENDPOINT &&
|
|
98
|
+
!promptOptions.function &&
|
|
99
|
+
!promptOptions.endpoint
|
|
100
|
+
);
|
|
101
|
+
},
|
|
51
102
|
},
|
|
52
103
|
]);
|
|
53
104
|
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const { getCwd } = require('@hubspot/cli-lib/path');
|
|
3
|
+
const { promptUser } = require('./promptUtils');
|
|
4
|
+
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
5
|
+
|
|
6
|
+
const i18nKey = 'cli.lib.prompts.uploadPrompt';
|
|
7
|
+
|
|
8
|
+
const uploadPrompt = (promptOptions = {}) => {
|
|
9
|
+
return promptUser([
|
|
10
|
+
{
|
|
11
|
+
name: 'src',
|
|
12
|
+
message: i18n(`${i18nKey}.enterSrc`),
|
|
13
|
+
when: !promptOptions.src,
|
|
14
|
+
default: '.',
|
|
15
|
+
validate: input => {
|
|
16
|
+
if (!input) {
|
|
17
|
+
return i18n(`${i18nKey}.errors.srcRequired`);
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'dest',
|
|
24
|
+
message: i18n(`${i18nKey}.enterDest`),
|
|
25
|
+
when: !promptOptions.dest,
|
|
26
|
+
default: path.basename(getCwd()),
|
|
27
|
+
validate: input => {
|
|
28
|
+
if (!input) {
|
|
29
|
+
return i18n(`${i18nKey}.errors.destRequired`);
|
|
30
|
+
}
|
|
31
|
+
return true;
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
]);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
module.exports = {
|
|
38
|
+
uploadPrompt,
|
|
39
|
+
};
|
package/lib/serverlessLogs.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const https = require('https');
|
|
2
2
|
const Spinnies = require('spinnies');
|
|
3
|
+
const chalk = require('chalk');
|
|
3
4
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
4
5
|
const { outputLogs } = require('@hubspot/cli-lib/lib/logs');
|
|
5
6
|
const {
|
|
@@ -17,6 +18,7 @@ const TAIL_DELAY = 5000;
|
|
|
17
18
|
const handleUserInput = spinnies => {
|
|
18
19
|
const onTerminate = async () => {
|
|
19
20
|
spinnies.remove('tailLogs');
|
|
21
|
+
spinnies.remove('stopMessage');
|
|
20
22
|
process.exit(EXIT_CODES.SUCCESS);
|
|
21
23
|
};
|
|
22
24
|
|
|
@@ -83,7 +85,11 @@ const tailLogs = async ({
|
|
|
83
85
|
const spinnies = new Spinnies();
|
|
84
86
|
|
|
85
87
|
spinnies.add('tailLogs', {
|
|
86
|
-
text: `Following logs for ${name}
|
|
88
|
+
text: `Following logs for ${name}`,
|
|
89
|
+
});
|
|
90
|
+
spinnies.add('stopMessage', {
|
|
91
|
+
text: `> Press ${chalk.bold('q')} to stop following`,
|
|
92
|
+
status: 'non-spinnable',
|
|
87
93
|
});
|
|
88
94
|
|
|
89
95
|
handleUserInput(spinnies);
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const hasFlag = require('./hasFlag');
|
|
3
|
+
|
|
4
|
+
//See https://github.com/jamestalmage/supports-hyperlinks (License: https://github.com/jamestalmage/supports-hyperlinks/blob/master/license)
|
|
5
|
+
|
|
6
|
+
function parseVersion(versionString) {
|
|
7
|
+
if (/^\d{3,4}$/.test(versionString)) {
|
|
8
|
+
// Env var doesn't always use dots. example: 4601 => 46.1.0
|
|
9
|
+
const m = /(\d{1,2})(\d{2})/.exec(versionString);
|
|
10
|
+
return {
|
|
11
|
+
major: 0,
|
|
12
|
+
minor: parseInt(m[1], 10),
|
|
13
|
+
patch: parseInt(m[2], 10),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const versions = (versionString || '').split('.').map(n => parseInt(n, 10));
|
|
18
|
+
return {
|
|
19
|
+
major: versions[0],
|
|
20
|
+
minor: versions[1],
|
|
21
|
+
patch: versions[2],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function supportsHyperlink(stream) {
|
|
26
|
+
const { env } = process;
|
|
27
|
+
|
|
28
|
+
if (hasFlag('noHyperlinks')) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (stream && !stream.isTTY) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (process.platform === 'win32') {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if ('CI' in env) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if ('TERM_PROGRAM' in env) {
|
|
45
|
+
const version = parseVersion(env.TERM_PROGRAM_VERSION);
|
|
46
|
+
|
|
47
|
+
switch (env.TERM_PROGRAM) {
|
|
48
|
+
case 'iTerm.app':
|
|
49
|
+
if (version.major === 3) {
|
|
50
|
+
return version.minor >= 1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return version.major > 3;
|
|
54
|
+
// No default
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if ('VTE_VERSION' in env) {
|
|
59
|
+
// 0.50.0 was supposed to support hyperlinks, but throws a segfault
|
|
60
|
+
if (env.VTE_VERSION === '0.50.0') {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const version = parseVersion(env.VTE_VERSION);
|
|
65
|
+
return version.major > 0 || version.minor >= 50;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = {
|
|
72
|
+
supportsHyperlink,
|
|
73
|
+
stdout: supportsHyperlink(process.stdout),
|
|
74
|
+
stderr: supportsHyperlink(process.stderr),
|
|
75
|
+
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
const process = require('process');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const tty = require('tty');
|
|
4
|
+
const hasFlag = require('./hasFlag');
|
|
5
|
+
|
|
6
|
+
const { env } = process;
|
|
7
|
+
|
|
8
|
+
//From: https://github.com/chalk/supports-color/blob/main/index.js (License: https://github.com/chalk/supports-color/blob/main/license)
|
|
9
|
+
|
|
10
|
+
function translateLevel(level) {
|
|
11
|
+
if (level === 0) {
|
|
12
|
+
return {
|
|
13
|
+
level,
|
|
14
|
+
hasBasic: false,
|
|
15
|
+
has256: false,
|
|
16
|
+
has16m: false,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
level,
|
|
22
|
+
hasBasic: true,
|
|
23
|
+
has256: level >= 2,
|
|
24
|
+
has16m: level >= 3,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function _supportsColor(haveStream, { streamIsTTY } = {}) {
|
|
29
|
+
if (haveStream && !streamIsTTY) {
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const min = 0;
|
|
34
|
+
|
|
35
|
+
if (env.TERM === 'dumb') {
|
|
36
|
+
return min;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (hasFlag('noColor')) {
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (process.platform === 'win32') {
|
|
44
|
+
// Windows 10 build 10586 is the first Windows release that supports 256 colors.
|
|
45
|
+
// Windows 10 build 14931 is the first release that supports 16m/TrueColor.
|
|
46
|
+
const osRelease = os.release().split('.');
|
|
47
|
+
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
48
|
+
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return 1;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if ('CI' in env) {
|
|
55
|
+
if (
|
|
56
|
+
[
|
|
57
|
+
'TRAVIS',
|
|
58
|
+
'CIRCLECI',
|
|
59
|
+
'APPVEYOR',
|
|
60
|
+
'GITLAB_CI',
|
|
61
|
+
'GITHUB_ACTIONS',
|
|
62
|
+
'BUILDKITE',
|
|
63
|
+
'DRONE',
|
|
64
|
+
].some(sign => sign in env) ||
|
|
65
|
+
env.CI_NAME === 'codeship'
|
|
66
|
+
) {
|
|
67
|
+
return 1;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return min;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Check for Azure DevOps pipelines
|
|
74
|
+
if ('TF_BUILD' in env && 'AGENT_NAME' in env) {
|
|
75
|
+
return 1;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (env.COLORTERM === 'truecolor') {
|
|
79
|
+
return 3;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if ('TERM_PROGRAM' in env) {
|
|
83
|
+
const version = Number.parseInt(
|
|
84
|
+
(env.TERM_PROGRAM_VERSION || '').split('.')[0],
|
|
85
|
+
10
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
switch (env.TERM_PROGRAM) {
|
|
89
|
+
case 'iTerm.app':
|
|
90
|
+
return version >= 3 ? 3 : 2;
|
|
91
|
+
case 'Apple_Terminal':
|
|
92
|
+
return 2;
|
|
93
|
+
// No default
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (/-256(color)?$/i.test(env.TERM)) {
|
|
98
|
+
return 2;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (
|
|
102
|
+
/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)
|
|
103
|
+
) {
|
|
104
|
+
return 1;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if ('COLORTERM' in env) {
|
|
108
|
+
return 1;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return min;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function createSupportsColor(stream, options = {}) {
|
|
115
|
+
const level = _supportsColor(stream, {
|
|
116
|
+
streamIsTTY: stream && stream.isTTY,
|
|
117
|
+
...options,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
return translateLevel(level);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const supportsColor = {
|
|
124
|
+
createSupportsColor,
|
|
125
|
+
stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
|
|
126
|
+
stderr: createSupportsColor({ isTTY: tty.isatty(2) }),
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
module.exports = supportsColor;
|
package/lib/ui.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
-
const supportsHyperlinks = require('
|
|
2
|
+
const supportsHyperlinks = require('../lib/supportHyperlinks');
|
|
3
|
+
const supportsColor = require('../lib/supportsColor');
|
|
3
4
|
const { getAccountConfig } = require('@hubspot/cli-lib/lib/config');
|
|
4
5
|
const { logger } = require('@hubspot/cli-lib/logger');
|
|
5
6
|
|
|
@@ -12,6 +13,19 @@ const uiLine = () => {
|
|
|
12
13
|
logger.log('-'.repeat(50));
|
|
13
14
|
};
|
|
14
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Returns an object that aggregates what the terminal supports (eg. hyperlinks and color)
|
|
18
|
+
*
|
|
19
|
+
* @returns {object}
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const getTerminalUISupport = () => {
|
|
23
|
+
return {
|
|
24
|
+
hyperlinks: supportsHyperlinks.stdout,
|
|
25
|
+
color: supportsColor.stdout.hasBasic,
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
|
|
15
29
|
/**
|
|
16
30
|
* Returns a hyperlink or link and description
|
|
17
31
|
*
|
|
@@ -20,8 +34,9 @@ const uiLine = () => {
|
|
|
20
34
|
* @param {object} options
|
|
21
35
|
* @returns {string}
|
|
22
36
|
*/
|
|
23
|
-
const uiLink = (linkText, url
|
|
24
|
-
|
|
37
|
+
const uiLink = (linkText, url) => {
|
|
38
|
+
const terminalUISupport = getTerminalUISupport();
|
|
39
|
+
if (terminalUISupport.hyperlinks) {
|
|
25
40
|
const result = [
|
|
26
41
|
'\u001B]8;;',
|
|
27
42
|
url,
|
|
@@ -29,9 +44,11 @@ const uiLink = (linkText, url, options = {}) => {
|
|
|
29
44
|
linkText,
|
|
30
45
|
'\u001B]8;;\u0007',
|
|
31
46
|
].join('');
|
|
32
|
-
return
|
|
47
|
+
return terminalUISupport.color ? chalk.cyan(result) : result;
|
|
33
48
|
} else {
|
|
34
|
-
return
|
|
49
|
+
return terminalUISupport.color
|
|
50
|
+
? `${linkText}: ${chalk.cyan(url)}`
|
|
51
|
+
: `${linkText}: ${url}`;
|
|
35
52
|
}
|
|
36
53
|
};
|
|
37
54
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
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.0",
|
|
12
|
+
"@hubspot/serverless-dev-runtime": "4.0.0",
|
|
13
13
|
"archiver": "^5.3.0",
|
|
14
14
|
"chalk": "^4.1.2",
|
|
15
15
|
"express": "^4.17.1",
|
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
"open": "^7.0.3",
|
|
21
21
|
"ora": "^4.0.3",
|
|
22
22
|
"spinnies": "^0.5.1",
|
|
23
|
-
"supports-hyperlinks": "^2.2.0",
|
|
24
23
|
"tmp": "^0.2.1",
|
|
25
24
|
"update-notifier": "^5.1.0",
|
|
26
25
|
"yargs": "15.4.1"
|
|
@@ -38,5 +37,5 @@
|
|
|
38
37
|
"publishConfig": {
|
|
39
38
|
"access": "public"
|
|
40
39
|
},
|
|
41
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "c11f159c8768c0a0beac7b221d4c2489bcf0064d"
|
|
42
41
|
}
|