@hubspot/cli 4.0.1-beta.5 → 4.0.2-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 +2 -0
- package/commands/process.js +85 -0
- package/commands/sandbox/create.js +4 -2
- package/commands/sandbox/delete.js +11 -3
- package/commands/upload.js +122 -16
- package/commands/watch.js +20 -1
- package/lib/projects.js +18 -4
- package/lib/prompts/cmsFieldPrompt.js +50 -0
- package/package.json +4 -4
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 processCommand = require('../commands/process');
|
|
38
39
|
const cmsCommand = require('../commands/cms');
|
|
39
40
|
const { EXIT_CODES } = require('../lib/enums/exitCodes');
|
|
40
41
|
|
|
@@ -154,6 +155,7 @@ const argv = yargs
|
|
|
154
155
|
.command(configCommand)
|
|
155
156
|
.command(accountsCommand)
|
|
156
157
|
.command(sandboxesCommand)
|
|
158
|
+
.command(processCommand, false)
|
|
157
159
|
.help()
|
|
158
160
|
.recommendCommands()
|
|
159
161
|
.demandCommand(1, '')
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const { createIgnoreFilter } = require('@hubspot/cli-lib/ignoreRules');
|
|
4
|
+
const { isAllowedExtension } = require('@hubspot/cli-lib//path');
|
|
5
|
+
const { logger } = require('@hubspot/cli-lib/logger');
|
|
6
|
+
const { walk } = require('@hubspot/cli-lib/lib/walk');
|
|
7
|
+
const { getThemeJSONPath } = require('@hubspot/cli-lib/lib/files');
|
|
8
|
+
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
9
|
+
const {
|
|
10
|
+
FieldsJs,
|
|
11
|
+
isProcessableFieldsJs,
|
|
12
|
+
} = require('@hubspot/cli-lib/lib/handleFieldsJs');
|
|
13
|
+
const i18nKey = 'cli.commands.process';
|
|
14
|
+
|
|
15
|
+
exports.command = 'process';
|
|
16
|
+
exports.describe = false;
|
|
17
|
+
|
|
18
|
+
const invalidPath = src => {
|
|
19
|
+
logger.error(
|
|
20
|
+
i18n(`${i18nKey}.errors.invalidPath`, {
|
|
21
|
+
path: src,
|
|
22
|
+
})
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
exports.handler = async options => {
|
|
27
|
+
const src = options.src;
|
|
28
|
+
const projectRoot = path.dirname(getThemeJSONPath(src));
|
|
29
|
+
let stats;
|
|
30
|
+
try {
|
|
31
|
+
stats = fs.statSync(src);
|
|
32
|
+
if (!stats.isFile() && !stats.isDirectory()) {
|
|
33
|
+
invalidPath(src);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
} catch (e) {
|
|
37
|
+
invalidPath(src);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (stats.isFile()) {
|
|
41
|
+
const fieldsJs = await new FieldsJs(
|
|
42
|
+
projectRoot,
|
|
43
|
+
src,
|
|
44
|
+
undefined,
|
|
45
|
+
options.fieldOptions
|
|
46
|
+
).init();
|
|
47
|
+
if (fieldsJs.rejected) return;
|
|
48
|
+
fieldsJs.saveOutput();
|
|
49
|
+
} else if (stats.isDirectory()) {
|
|
50
|
+
const filePaths = await walk(src);
|
|
51
|
+
const allowedFilePaths = filePaths
|
|
52
|
+
.filter(file => {
|
|
53
|
+
if (!isAllowedExtension(file)) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
})
|
|
58
|
+
.filter(createIgnoreFilter());
|
|
59
|
+
for (const filePath of allowedFilePaths) {
|
|
60
|
+
if (isProcessableFieldsJs(projectRoot, filePath, true)) {
|
|
61
|
+
const fieldsJs = await new FieldsJs(
|
|
62
|
+
projectRoot,
|
|
63
|
+
filePath,
|
|
64
|
+
undefined,
|
|
65
|
+
options.fieldOptions
|
|
66
|
+
).init();
|
|
67
|
+
if (fieldsJs.rejected) return;
|
|
68
|
+
fieldsJs.saveOutput();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
exports.builder = yargs => {
|
|
75
|
+
yargs.positional('src', {
|
|
76
|
+
describe: i18n(`${i18nKey}.positionals.src.describe`),
|
|
77
|
+
type: 'string',
|
|
78
|
+
});
|
|
79
|
+
yargs.option('fieldOptions', {
|
|
80
|
+
describe: i18n(`${i18nKey}.options.options.describe`),
|
|
81
|
+
type: 'array',
|
|
82
|
+
default: [''],
|
|
83
|
+
});
|
|
84
|
+
return yargs;
|
|
85
|
+
};
|
|
@@ -120,10 +120,10 @@ exports.handler = async options => {
|
|
|
120
120
|
succeedColor: 'white',
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
-
let namePrompt;
|
|
124
|
-
|
|
125
123
|
trackCommandUsage('sandbox-create', {}, accountId);
|
|
126
124
|
|
|
125
|
+
let namePrompt;
|
|
126
|
+
|
|
127
127
|
if (!name) {
|
|
128
128
|
namePrompt = await createSandboxPrompt();
|
|
129
129
|
}
|
|
@@ -151,6 +151,8 @@ exports.handler = async options => {
|
|
|
151
151
|
} catch (err) {
|
|
152
152
|
debugErrorAndContext(err);
|
|
153
153
|
|
|
154
|
+
trackCommandUsage('sandbox-create', { success: false }, accountId);
|
|
155
|
+
|
|
154
156
|
spinnies.fail('sandboxCreate', {
|
|
155
157
|
text: i18n(`${i18nKey}.loading.fail`, {
|
|
156
158
|
sandboxName,
|
|
@@ -16,7 +16,9 @@ const { deleteSandbox } = require('@hubspot/cli-lib/sandboxes');
|
|
|
16
16
|
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
17
17
|
const { getConfig, getEnv } = require('@hubspot/cli-lib');
|
|
18
18
|
const { deleteSandboxPrompt } = require('../../lib/prompts/sandboxesPrompt');
|
|
19
|
-
const {
|
|
19
|
+
const {
|
|
20
|
+
removeSandboxAccountFromConfig,
|
|
21
|
+
} = require('@hubspot/cli-lib/lib/config');
|
|
20
22
|
const {
|
|
21
23
|
selectAndSetAsDefaultAccountPrompt,
|
|
22
24
|
} = require('../../lib/prompts/accountsPrompt');
|
|
@@ -114,7 +116,9 @@ exports.handler = async options => {
|
|
|
114
116
|
);
|
|
115
117
|
logger.log('');
|
|
116
118
|
|
|
117
|
-
const promptDefaultAccount =
|
|
119
|
+
const promptDefaultAccount = removeSandboxAccountFromConfig(
|
|
120
|
+
sandboxAccountId
|
|
121
|
+
);
|
|
118
122
|
if (promptDefaultAccount) {
|
|
119
123
|
await selectAndSetAsDefaultAccountPrompt(config);
|
|
120
124
|
}
|
|
@@ -122,6 +126,8 @@ exports.handler = async options => {
|
|
|
122
126
|
} catch (err) {
|
|
123
127
|
debugErrorAndContext(err);
|
|
124
128
|
|
|
129
|
+
trackCommandUsage('sandbox-delete', { success: false }, sandboxAccountId);
|
|
130
|
+
|
|
125
131
|
if (
|
|
126
132
|
err.error &&
|
|
127
133
|
err.error.category === OBJECT_NOT_FOUND &&
|
|
@@ -135,7 +141,9 @@ exports.handler = async options => {
|
|
|
135
141
|
);
|
|
136
142
|
logger.log('');
|
|
137
143
|
|
|
138
|
-
const promptDefaultAccount =
|
|
144
|
+
const promptDefaultAccount = removeSandboxAccountFromConfig(
|
|
145
|
+
sandboxAccountId
|
|
146
|
+
);
|
|
139
147
|
if (promptDefaultAccount) {
|
|
140
148
|
await selectAndSetAsDefaultAccountPrompt(config);
|
|
141
149
|
}
|
package/commands/upload.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
|
|
3
|
+
const { walk } = require('@hubspot/cli-lib/lib/walk');
|
|
4
|
+
const { createIgnoreFilter } = require('@hubspot/cli-lib/ignoreRules');
|
|
4
5
|
const { uploadFolder, hasUploadErrors } = require('@hubspot/cli-lib');
|
|
5
6
|
const { getFileMapperQueryValues } = require('@hubspot/cli-lib/fileMapper');
|
|
6
7
|
const { upload } = require('@hubspot/cli-lib/api/fileMapper');
|
|
@@ -27,13 +28,21 @@ const {
|
|
|
27
28
|
getMode,
|
|
28
29
|
} = require('../lib/commonOpts');
|
|
29
30
|
const { uploadPrompt } = require('../lib/prompts/uploadPrompt');
|
|
31
|
+
const { fieldsJsPrompt } = require('../lib/prompts/cmsFieldPrompt');
|
|
30
32
|
const { validateMode, loadAndValidateOptions } = require('../lib/validation');
|
|
31
33
|
const { trackCommandUsage } = require('../lib/usageTracking');
|
|
32
|
-
const {
|
|
34
|
+
const {
|
|
35
|
+
getThemePreviewUrl,
|
|
36
|
+
getThemeJSONPath,
|
|
37
|
+
} = require('@hubspot/cli-lib/lib/files');
|
|
33
38
|
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
34
|
-
|
|
35
39
|
const i18nKey = 'cli.commands.upload';
|
|
36
40
|
const { EXIT_CODES } = require('../lib/enums/exitCodes');
|
|
41
|
+
const {
|
|
42
|
+
FieldsJs,
|
|
43
|
+
isProcessableFieldsJs,
|
|
44
|
+
cleanupTmpDirSync,
|
|
45
|
+
} = require('@hubspot/cli-lib/lib/handleFieldsJs');
|
|
37
46
|
|
|
38
47
|
exports.command = 'upload [--src] [--dest]';
|
|
39
48
|
exports.describe = i18n(`${i18nKey}.describe`);
|
|
@@ -61,11 +70,34 @@ exports.handler = async options => {
|
|
|
61
70
|
const mode = getMode(options);
|
|
62
71
|
|
|
63
72
|
const uploadPromptAnswers = await uploadPrompt(options);
|
|
64
|
-
|
|
65
73
|
const src = options.src || uploadPromptAnswers.src;
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
74
|
+
const saveOutput = options.saveOutput;
|
|
75
|
+
let dest = options.dest || uploadPromptAnswers.dest;
|
|
76
|
+
let absoluteSrcPath = path.resolve(getCwd(), src);
|
|
77
|
+
if (!dest) {
|
|
78
|
+
logger.error(i18n(`${i18nKey}.errors.destinationRequired`));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// The theme.json file must always be at the root of the project - so we look for that and determine the root path based on it.
|
|
82
|
+
const projectRoot = path.dirname(getThemeJSONPath(absoluteSrcPath));
|
|
83
|
+
const processFieldsJs = isProcessableFieldsJs(
|
|
84
|
+
projectRoot,
|
|
85
|
+
absoluteSrcPath,
|
|
86
|
+
options.processFieldsJs
|
|
87
|
+
);
|
|
88
|
+
let fieldsJs;
|
|
89
|
+
if (processFieldsJs) {
|
|
90
|
+
fieldsJs = await new FieldsJs(
|
|
91
|
+
projectRoot,
|
|
92
|
+
absoluteSrcPath,
|
|
93
|
+
undefined,
|
|
94
|
+
options.fieldOptions
|
|
95
|
+
).init();
|
|
96
|
+
if (fieldsJs.rejected) return;
|
|
97
|
+
// Ensures that the dest path is a .json. The user might pass '.js' accidentally - this ensures it just works.
|
|
98
|
+
absoluteSrcPath = fieldsJs.outputPath;
|
|
99
|
+
dest = path.join(path.dirname(dest), 'fields.json');
|
|
100
|
+
}
|
|
69
101
|
let stats;
|
|
70
102
|
try {
|
|
71
103
|
stats = fs.statSync(absoluteSrcPath);
|
|
@@ -86,10 +118,6 @@ exports.handler = async options => {
|
|
|
86
118
|
return;
|
|
87
119
|
}
|
|
88
120
|
|
|
89
|
-
if (!dest) {
|
|
90
|
-
logger.error(i18n(`${i18nKey}.errors.destinationRequired`));
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
121
|
const normalizedDest = convertToUnixPath(dest);
|
|
94
122
|
trackCommandUsage(
|
|
95
123
|
'upload',
|
|
@@ -106,7 +134,7 @@ exports.handler = async options => {
|
|
|
106
134
|
process.exit(EXIT_CODES.WARNING);
|
|
107
135
|
}
|
|
108
136
|
if (stats.isFile()) {
|
|
109
|
-
if (!isAllowedExtension(src)) {
|
|
137
|
+
if (!isAllowedExtension(src) && !processFieldsJs) {
|
|
110
138
|
logger.error(
|
|
111
139
|
i18n(`${i18nKey}.errors.invalidPath`, {
|
|
112
140
|
path: src,
|
|
@@ -123,7 +151,6 @@ exports.handler = async options => {
|
|
|
123
151
|
);
|
|
124
152
|
return;
|
|
125
153
|
}
|
|
126
|
-
|
|
127
154
|
upload(
|
|
128
155
|
accountId,
|
|
129
156
|
absoluteSrcPath,
|
|
@@ -156,6 +183,13 @@ exports.handler = async options => {
|
|
|
156
183
|
})
|
|
157
184
|
);
|
|
158
185
|
process.exit(EXIT_CODES.WARNING);
|
|
186
|
+
})
|
|
187
|
+
.finally(() => {
|
|
188
|
+
if (!processFieldsJs) return;
|
|
189
|
+
if (saveOutput) {
|
|
190
|
+
fieldsJs.saveOutput();
|
|
191
|
+
}
|
|
192
|
+
cleanupTmpDirSync(fieldsJs.rootWriteDir);
|
|
159
193
|
});
|
|
160
194
|
} else {
|
|
161
195
|
logger.log(
|
|
@@ -165,9 +199,22 @@ exports.handler = async options => {
|
|
|
165
199
|
src,
|
|
166
200
|
})
|
|
167
201
|
);
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
202
|
+
|
|
203
|
+
// Generate the first-pass file list in here, and pass to uploadFolder.
|
|
204
|
+
const filePaths = await getUploadableFileList(
|
|
205
|
+
absoluteSrcPath,
|
|
206
|
+
options.processFieldsJs
|
|
207
|
+
);
|
|
208
|
+
uploadFolder(
|
|
209
|
+
accountId,
|
|
210
|
+
absoluteSrcPath,
|
|
211
|
+
dest,
|
|
212
|
+
{
|
|
213
|
+
mode,
|
|
214
|
+
},
|
|
215
|
+
options,
|
|
216
|
+
filePaths
|
|
217
|
+
)
|
|
171
218
|
.then(results => {
|
|
172
219
|
if (!hasUploadErrors(results)) {
|
|
173
220
|
logger.success(
|
|
@@ -200,6 +247,46 @@ exports.handler = async options => {
|
|
|
200
247
|
}
|
|
201
248
|
};
|
|
202
249
|
|
|
250
|
+
/*
|
|
251
|
+
* Walks the src folder for files, filters them based on ignore filter.
|
|
252
|
+
* If processFieldsJs is true then will check for any JS fields conflicts (i.e., JS fields file and fields.json file) and prompt to resolve
|
|
253
|
+
*/
|
|
254
|
+
const getUploadableFileList = async (src, processFieldsJs) => {
|
|
255
|
+
const filePaths = await walk(src);
|
|
256
|
+
const allowedFiles = filePaths
|
|
257
|
+
.filter(file => {
|
|
258
|
+
if (!isAllowedExtension(file)) {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
return true;
|
|
262
|
+
})
|
|
263
|
+
.filter(createIgnoreFilter());
|
|
264
|
+
if (!processFieldsJs) {
|
|
265
|
+
return allowedFiles;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
let uploadableFiles = [];
|
|
269
|
+
let skipFiles = [];
|
|
270
|
+
for (const filePath of allowedFiles) {
|
|
271
|
+
const fileName = path.basename(filePath);
|
|
272
|
+
if (skipFiles.includes(filePath)) continue;
|
|
273
|
+
const isProcessable = isProcessableFieldsJs(src, filePath, processFieldsJs);
|
|
274
|
+
if (isProcessable || fileName == 'fields.json') {
|
|
275
|
+
// This prompt checks if there are multiple field files in the folder and gets user to choose.
|
|
276
|
+
const [choice, updatedSkipFiles] = await fieldsJsPrompt(
|
|
277
|
+
filePath,
|
|
278
|
+
src,
|
|
279
|
+
skipFiles
|
|
280
|
+
);
|
|
281
|
+
skipFiles = updatedSkipFiles;
|
|
282
|
+
// If they chose something other than the current file, move on.
|
|
283
|
+
if (choice !== filePath) continue;
|
|
284
|
+
}
|
|
285
|
+
uploadableFiles.push(filePath);
|
|
286
|
+
}
|
|
287
|
+
return uploadableFiles;
|
|
288
|
+
};
|
|
289
|
+
|
|
203
290
|
exports.builder = yargs => {
|
|
204
291
|
addConfigOptions(yargs, true);
|
|
205
292
|
addAccountOptions(yargs, true);
|
|
@@ -214,5 +301,24 @@ exports.builder = yargs => {
|
|
|
214
301
|
describe: i18n(`${i18nKey}.positionals.dest.describe`),
|
|
215
302
|
type: 'string',
|
|
216
303
|
});
|
|
304
|
+
yargs.option('fieldOptions', {
|
|
305
|
+
describe: i18n(`${i18nKey}.options.options.describe`),
|
|
306
|
+
type: 'array',
|
|
307
|
+
default: [''],
|
|
308
|
+
hidden: true,
|
|
309
|
+
});
|
|
310
|
+
yargs.option('saveOutput', {
|
|
311
|
+
describe: i18n(`${i18nKey}.options.saveOutput.describe`),
|
|
312
|
+
type: 'boolean',
|
|
313
|
+
default: false,
|
|
314
|
+
hidden: true,
|
|
315
|
+
});
|
|
316
|
+
yargs.option('processFieldsJs', {
|
|
317
|
+
describe: i18n(`${i18nKey}.options.processFields.describe`),
|
|
318
|
+
alias: ['processFields'],
|
|
319
|
+
type: 'boolean',
|
|
320
|
+
default: false,
|
|
321
|
+
hidden: true,
|
|
322
|
+
});
|
|
217
323
|
return yargs;
|
|
218
324
|
};
|
package/commands/watch.js
CHANGED
|
@@ -82,6 +82,7 @@ exports.handler = async options => {
|
|
|
82
82
|
remove,
|
|
83
83
|
disableInitial: initialUpload ? false : true,
|
|
84
84
|
notify,
|
|
85
|
+
commandOptions: options,
|
|
85
86
|
});
|
|
86
87
|
};
|
|
87
88
|
|
|
@@ -99,6 +100,12 @@ exports.builder = yargs => {
|
|
|
99
100
|
describe: i18n(`${i18nKey}.positionals.dest.describe`),
|
|
100
101
|
type: 'string',
|
|
101
102
|
});
|
|
103
|
+
yargs.option('fieldOptions', {
|
|
104
|
+
describe: i18n(`${i18nKey}.options.options.describe`),
|
|
105
|
+
type: 'array',
|
|
106
|
+
default: [''],
|
|
107
|
+
hidden: true,
|
|
108
|
+
});
|
|
102
109
|
yargs.option('remove', {
|
|
103
110
|
alias: 'r',
|
|
104
111
|
describe: i18n(`${i18nKey}.options.remove.describe`),
|
|
@@ -121,6 +128,18 @@ exports.builder = yargs => {
|
|
|
121
128
|
type: 'string',
|
|
122
129
|
requiresArg: true,
|
|
123
130
|
});
|
|
124
|
-
|
|
131
|
+
yargs.option('processFieldsJs', {
|
|
132
|
+
describe: i18n(`${i18nKey}.options.processFields.describe`),
|
|
133
|
+
alias: ['processFields'],
|
|
134
|
+
type: 'boolean',
|
|
135
|
+
default: false,
|
|
136
|
+
hidden: true,
|
|
137
|
+
});
|
|
138
|
+
yargs.option('saveOutput', {
|
|
139
|
+
describe: i18n(`${i18nKey}.options.saveOutput.describe`),
|
|
140
|
+
type: 'boolean',
|
|
141
|
+
default: false,
|
|
142
|
+
hidden: true,
|
|
143
|
+
});
|
|
125
144
|
return yargs;
|
|
126
145
|
};
|
package/lib/projects.js
CHANGED
|
@@ -224,6 +224,13 @@ const getProjectBuildDetailUrl = (projectName, buildId, accountId) => {
|
|
|
224
224
|
return `${getProjectDetailUrl(projectName, accountId)}/build/${buildId}`;
|
|
225
225
|
};
|
|
226
226
|
|
|
227
|
+
const getProjectDeployDetailUrl = (projectName, deployId, accountId) => {
|
|
228
|
+
if (!projectName || !deployId || !accountId) return;
|
|
229
|
+
return `${getProjectDetailUrl(
|
|
230
|
+
projectName,
|
|
231
|
+
accountId
|
|
232
|
+
)}/activity/deploy/${deployId}`;
|
|
233
|
+
};
|
|
227
234
|
const uploadProjectFiles = async (accountId, projectName, filePath) => {
|
|
228
235
|
const i18nKey = 'cli.commands.project.subcommands.upload';
|
|
229
236
|
const spinnies = new Spinnies({
|
|
@@ -347,7 +354,9 @@ const makePollTaskStatusFunc = ({
|
|
|
347
354
|
const displayId = deployedBuildId || taskId;
|
|
348
355
|
|
|
349
356
|
if (linkToHubSpot) {
|
|
350
|
-
logger.log(
|
|
357
|
+
logger.log(
|
|
358
|
+
`\n${linkToHubSpot(accountId, taskName, taskId, deployedBuildId)}\n`
|
|
359
|
+
);
|
|
351
360
|
}
|
|
352
361
|
|
|
353
362
|
const spinnies = new Spinnies({
|
|
@@ -471,10 +480,10 @@ const makePollTaskStatusFunc = ({
|
|
|
471
480
|
};
|
|
472
481
|
|
|
473
482
|
const pollBuildStatus = makePollTaskStatusFunc({
|
|
474
|
-
linkToHubSpot: (
|
|
483
|
+
linkToHubSpot: (accountId, taskName, taskId) =>
|
|
475
484
|
uiLink(
|
|
476
|
-
`View build #${
|
|
477
|
-
getProjectBuildDetailUrl(
|
|
485
|
+
`View build #${taskId} in HubSpot`,
|
|
486
|
+
getProjectBuildDetailUrl(taskName, taskId, accountId)
|
|
478
487
|
),
|
|
479
488
|
statusFn: getBuildStatus,
|
|
480
489
|
statusText: PROJECT_BUILD_TEXT,
|
|
@@ -490,6 +499,11 @@ const pollBuildStatus = makePollTaskStatusFunc({
|
|
|
490
499
|
});
|
|
491
500
|
|
|
492
501
|
const pollDeployStatus = makePollTaskStatusFunc({
|
|
502
|
+
linkToHubSpot: (accountId, taskName, taskId, deployedBuildId) =>
|
|
503
|
+
uiLink(
|
|
504
|
+
`View deploy of build #${deployedBuildId} in HubSpot`,
|
|
505
|
+
getProjectDeployDetailUrl(taskName, taskId, accountId)
|
|
506
|
+
),
|
|
493
507
|
statusFn: getDeployStatus,
|
|
494
508
|
statusText: PROJECT_DEPLOY_TEXT,
|
|
495
509
|
statusStrings: {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const { promptUser } = require('./promptUtils');
|
|
4
|
+
const { i18n } = require('@hubspot/cli-lib/lib/lang');
|
|
5
|
+
const escapeRegExp = require('@hubspot/cli-lib/lib/escapeRegExp');
|
|
6
|
+
const i18nKey = 'cli.lib.prompts.uploadPrompt';
|
|
7
|
+
const FIELDS_FILES = ['fields.json', 'fields.js', 'fields.cjs', 'fields.mjs'];
|
|
8
|
+
|
|
9
|
+
const fieldsJsPrompt = async (filePath, projectDir, skipFiles = []) => {
|
|
10
|
+
const dirName = path.dirname(filePath);
|
|
11
|
+
|
|
12
|
+
// Get a list of all field files in the directory, resolve their absolute path, and remove the ones that we already skipped.
|
|
13
|
+
const fileChoices = fs
|
|
14
|
+
.readdirSync(dirName)
|
|
15
|
+
.filter(file => FIELDS_FILES.includes(file))
|
|
16
|
+
.map(file => path.resolve(dirName, file))
|
|
17
|
+
.filter(file => !skipFiles.includes(file));
|
|
18
|
+
|
|
19
|
+
if (!fileChoices.length) return [filePath, []];
|
|
20
|
+
if (fileChoices.length == 1) return [fileChoices[0], []];
|
|
21
|
+
|
|
22
|
+
// We get the directory above the project one so that relative paths are printed with the root of the project dir attached.
|
|
23
|
+
projectDir = projectDir.substring(0, projectDir.lastIndexOf('/'));
|
|
24
|
+
const projectDirRegex = new RegExp(`^${escapeRegExp(projectDir)}`);
|
|
25
|
+
const fileDir = path.dirname(fileChoices[0]).replace(projectDirRegex, '');
|
|
26
|
+
|
|
27
|
+
const selection = [];
|
|
28
|
+
fileChoices.forEach(fileChoice => {
|
|
29
|
+
selection.push({
|
|
30
|
+
name: fileChoice.replace(projectDirRegex, ''),
|
|
31
|
+
value: fileChoice,
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
const promptVal = await promptUser([
|
|
35
|
+
{
|
|
36
|
+
message: i18n(`${i18nKey}.fieldsPrompt`, { dir: fileDir }),
|
|
37
|
+
type: 'list',
|
|
38
|
+
name: 'filePathChoice',
|
|
39
|
+
choices: selection,
|
|
40
|
+
},
|
|
41
|
+
]);
|
|
42
|
+
const choice = promptVal.filePathChoice;
|
|
43
|
+
|
|
44
|
+
// Add the ones that were not picked to skip files array.
|
|
45
|
+
const notPicked = fileChoices.filter(item => item !== choice);
|
|
46
|
+
skipFiles.push(...notPicked);
|
|
47
|
+
return [choice, skipFiles];
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
module.exports = { fieldsJsPrompt };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.2-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": "4.0.
|
|
12
|
-
"@hubspot/serverless-dev-runtime": "4.0.
|
|
11
|
+
"@hubspot/cli-lib": "4.0.2-beta.1",
|
|
12
|
+
"@hubspot/serverless-dev-runtime": "4.0.2-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": "75ff004ab82bfdf35107d602530237b6dd37ebee"
|
|
41
41
|
}
|