@featurevisor/cli 1.25.0 → 1.27.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/.eslintcache +1 -1
- package/CHANGELOG.md +19 -0
- package/lib/index.js +39 -550
- package/lib/index.js.map +1 -1
- package/package.json +3 -7
- package/src/index.ts +35 -438
package/.eslintcache
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
[{"/home/runner/work/featurevisor/featurevisor/packages/cli/bin.js":"1","/home/runner/work/featurevisor/featurevisor/packages/cli/src/index.ts":"2"},{"size":45,"mtime":
|
|
1
|
+
[{"/home/runner/work/featurevisor/featurevisor/packages/cli/bin.js":"1","/home/runner/work/featurevisor/featurevisor/packages/cli/src/index.ts":"2"},{"size":45,"mtime":1723067365530,"results":"3","hashOfConfig":"4"},{"size":1636,"mtime":1723067365530,"results":"5","hashOfConfig":"4"},{"filePath":"6","messages":"7","suppressedMessages":"8","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1sbluog",{"filePath":"9","messages":"10","suppressedMessages":"11","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/home/runner/work/featurevisor/featurevisor/packages/cli/bin.js",[],[],"/home/runner/work/featurevisor/featurevisor/packages/cli/src/index.ts",[],[]]
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [1.27.0](https://github.com/featurevisor/featurevisor/compare/v1.26.0...v1.27.0) (2024-08-07)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Plugins API ([#318](https://github.com/featurevisor/featurevisor/issues/318)) ([f86312b](https://github.com/featurevisor/featurevisor/commit/f86312bbf02466f2926783edd590e78e254060fd))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [1.26.0](https://github.com/featurevisor/featurevisor/compare/v1.25.0...v1.26.0) (2024-07-19)
|
|
18
|
+
|
|
19
|
+
**Note:** Version bump only for package @featurevisor/cli
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
6
25
|
# [1.25.0](https://github.com/featurevisor/featurevisor/compare/v1.24.0...v1.25.0) (2024-07-16)
|
|
7
26
|
|
|
8
27
|
|
package/lib/index.js
CHANGED
|
@@ -39,563 +39,52 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
var fs = require("fs");
|
|
40
40
|
var path = require("path");
|
|
41
41
|
var core_1 = require("@featurevisor/core");
|
|
42
|
-
var yargs = require("yargs"); // eslint-disable-line @typescript-eslint/no-var-requires
|
|
43
42
|
process.on("unhandledRejection", function (reason) {
|
|
44
43
|
console.error(reason);
|
|
45
44
|
process.exit(1);
|
|
46
45
|
});
|
|
47
|
-
function requireConfigFile(configModulePath) {
|
|
48
|
-
if (!fs.existsSync(configModulePath)) {
|
|
49
|
-
console.error("No config file found. Please create `featurevisor.config.js` file first.");
|
|
50
|
-
process.exit(1);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
function requireAndGetProjectConfig(rootDirectoryPath) {
|
|
54
|
-
var configModulePath = path.join(rootDirectoryPath, core_1.CONFIG_MODULE_NAME);
|
|
55
|
-
requireConfigFile(configModulePath);
|
|
56
|
-
return (0, core_1.getProjectConfig)(rootDirectoryPath);
|
|
57
|
-
}
|
|
58
|
-
var rootDirectoryPath = process.cwd();
|
|
59
|
-
function getDependencies(options) {
|
|
60
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
61
|
-
var useRootDirectoryPath, projectConfig, datasource;
|
|
62
|
-
return __generator(this, function (_a) {
|
|
63
|
-
useRootDirectoryPath = options.rootDirectoryPath || rootDirectoryPath;
|
|
64
|
-
projectConfig = requireAndGetProjectConfig(useRootDirectoryPath);
|
|
65
|
-
datasource = new core_1.Datasource(projectConfig, useRootDirectoryPath);
|
|
66
|
-
return [2 /*return*/, {
|
|
67
|
-
rootDirectoryPath: useRootDirectoryPath,
|
|
68
|
-
projectConfig: projectConfig,
|
|
69
|
-
datasource: datasource,
|
|
70
|
-
options: options,
|
|
71
|
-
}];
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
46
|
function main() {
|
|
76
47
|
return __awaiter(this, void 0, void 0, function () {
|
|
48
|
+
var rootDirectoryPath, argv, cliPackage, corePackage, useRootDirectoryPath, customRootDir, configModulePath, projectConfig, datasource;
|
|
77
49
|
return __generator(this, function (_a) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
deps = _a.sent();
|
|
117
|
-
lintOptions = {
|
|
118
|
-
keyPattern: options.keyPattern,
|
|
119
|
-
entityType: options.entityType,
|
|
120
|
-
};
|
|
121
|
-
return [4 /*yield*/, (0, core_1.lintProject)(deps, lintOptions)];
|
|
122
|
-
case 2:
|
|
123
|
-
hasError = _a.sent();
|
|
124
|
-
if (hasError) {
|
|
125
|
-
process.exit(1);
|
|
126
|
-
}
|
|
127
|
-
return [2 /*return*/];
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
},
|
|
132
|
-
})
|
|
133
|
-
.example("$0 lint", "lint all YAML file content")
|
|
134
|
-
/**
|
|
135
|
-
* Build
|
|
136
|
-
*/
|
|
137
|
-
.command({
|
|
138
|
-
command: "build",
|
|
139
|
-
handler: function (options) {
|
|
140
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
141
|
-
var deps, e_1;
|
|
142
|
-
return __generator(this, function (_a) {
|
|
143
|
-
switch (_a.label) {
|
|
144
|
-
case 0: return [4 /*yield*/, getDependencies(options)];
|
|
145
|
-
case 1:
|
|
146
|
-
deps = _a.sent();
|
|
147
|
-
_a.label = 2;
|
|
148
|
-
case 2:
|
|
149
|
-
_a.trys.push([2, 4, , 5]);
|
|
150
|
-
return [4 /*yield*/, (0, core_1.buildProject)(deps, options)];
|
|
151
|
-
case 3:
|
|
152
|
-
_a.sent();
|
|
153
|
-
return [3 /*break*/, 5];
|
|
154
|
-
case 4:
|
|
155
|
-
e_1 = _a.sent();
|
|
156
|
-
console.error(e_1);
|
|
157
|
-
process.exit(1);
|
|
158
|
-
return [3 /*break*/, 5];
|
|
159
|
-
case 5: return [2 /*return*/];
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
},
|
|
164
|
-
})
|
|
165
|
-
.example("$0 build", "build datafiles")
|
|
166
|
-
/**
|
|
167
|
-
* Restore
|
|
168
|
-
*/
|
|
169
|
-
.command({
|
|
170
|
-
command: "restore",
|
|
171
|
-
handler: function (options) {
|
|
172
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
173
|
-
var deps, e_2;
|
|
174
|
-
return __generator(this, function (_a) {
|
|
175
|
-
switch (_a.label) {
|
|
176
|
-
case 0: return [4 /*yield*/, getDependencies(options)];
|
|
177
|
-
case 1:
|
|
178
|
-
deps = _a.sent();
|
|
179
|
-
_a.label = 2;
|
|
180
|
-
case 2:
|
|
181
|
-
_a.trys.push([2, 4, , 5]);
|
|
182
|
-
return [4 /*yield*/, (0, core_1.restoreProject)(deps)];
|
|
183
|
-
case 3:
|
|
184
|
-
_a.sent();
|
|
185
|
-
return [3 /*break*/, 5];
|
|
186
|
-
case 4:
|
|
187
|
-
e_2 = _a.sent();
|
|
188
|
-
console.error(e_2.message);
|
|
189
|
-
process.exit(1);
|
|
190
|
-
return [3 /*break*/, 5];
|
|
191
|
-
case 5: return [2 /*return*/];
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
},
|
|
196
|
-
})
|
|
197
|
-
.example("$0 restore", "restore state files")
|
|
198
|
-
/**
|
|
199
|
-
* Test
|
|
200
|
-
*/
|
|
201
|
-
.command({
|
|
202
|
-
command: "test",
|
|
203
|
-
handler: function (options) {
|
|
204
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
205
|
-
var deps, testOptions, hasError;
|
|
206
|
-
return __generator(this, function (_a) {
|
|
207
|
-
switch (_a.label) {
|
|
208
|
-
case 0: return [4 /*yield*/, getDependencies(options)];
|
|
209
|
-
case 1:
|
|
210
|
-
deps = _a.sent();
|
|
211
|
-
testOptions = {
|
|
212
|
-
keyPattern: options.keyPattern,
|
|
213
|
-
assertionPattern: options.assertionPattern,
|
|
214
|
-
verbose: options.verbose || false,
|
|
215
|
-
showDatafile: options.showDatafile || false,
|
|
216
|
-
onlyFailures: options.onlyFailures || false,
|
|
217
|
-
};
|
|
218
|
-
return [4 /*yield*/, (0, core_1.testProject)(deps, testOptions)];
|
|
219
|
-
case 2:
|
|
220
|
-
hasError = _a.sent();
|
|
221
|
-
if (hasError) {
|
|
222
|
-
process.exit(1);
|
|
223
|
-
}
|
|
224
|
-
return [2 /*return*/];
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
});
|
|
228
|
-
},
|
|
229
|
-
})
|
|
230
|
-
.example("$0 test", "test features")
|
|
231
|
-
/**
|
|
232
|
-
* Site
|
|
233
|
-
*/
|
|
234
|
-
.command({
|
|
235
|
-
command: "site [subcommand]",
|
|
236
|
-
handler: function (options) {
|
|
237
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
238
|
-
var deps, allowedSubcommands, hasError;
|
|
239
|
-
return __generator(this, function (_a) {
|
|
240
|
-
switch (_a.label) {
|
|
241
|
-
case 0: return [4 /*yield*/, getDependencies(options)];
|
|
242
|
-
case 1:
|
|
243
|
-
deps = _a.sent();
|
|
244
|
-
allowedSubcommands = ["export", "serve"];
|
|
245
|
-
if (!allowedSubcommands.includes(options.subcommand)) {
|
|
246
|
-
console.log("Please specify a subcommand: `export` or `serve`");
|
|
247
|
-
return [2 /*return*/];
|
|
248
|
-
}
|
|
249
|
-
if (!(options.subcommand === "export")) return [3 /*break*/, 3];
|
|
250
|
-
return [4 /*yield*/, (0, core_1.exportSite)(deps)];
|
|
251
|
-
case 2:
|
|
252
|
-
hasError = _a.sent();
|
|
253
|
-
if (hasError) {
|
|
254
|
-
process.exit(1);
|
|
255
|
-
}
|
|
256
|
-
_a.label = 3;
|
|
257
|
-
case 3:
|
|
258
|
-
// serve
|
|
259
|
-
if (options.subcommand === "serve") {
|
|
260
|
-
(0, core_1.serveSite)(deps);
|
|
261
|
-
}
|
|
262
|
-
return [2 /*return*/];
|
|
263
|
-
}
|
|
264
|
-
});
|
|
265
|
-
});
|
|
266
|
-
},
|
|
267
|
-
})
|
|
268
|
-
.example("$0 site export", "generate static site with project data")
|
|
269
|
-
.example("$0 site serve", "serve already exported site locally")
|
|
270
|
-
.example("$0 site serve -p 3000", "serve in a specific port")
|
|
271
|
-
/**
|
|
272
|
-
* Generate code
|
|
273
|
-
*/
|
|
274
|
-
.command({
|
|
275
|
-
command: "generate-code",
|
|
276
|
-
handler: function (options) {
|
|
277
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
278
|
-
var deps, e_3;
|
|
279
|
-
return __generator(this, function (_a) {
|
|
280
|
-
switch (_a.label) {
|
|
281
|
-
case 0: return [4 /*yield*/, getDependencies(options)];
|
|
282
|
-
case 1:
|
|
283
|
-
deps = _a.sent();
|
|
284
|
-
_a.label = 2;
|
|
285
|
-
case 2:
|
|
286
|
-
_a.trys.push([2, 4, , 5]);
|
|
287
|
-
return [4 /*yield*/, (0, core_1.generateCodeForProject)(deps, options)];
|
|
288
|
-
case 3:
|
|
289
|
-
_a.sent();
|
|
290
|
-
return [3 /*break*/, 5];
|
|
291
|
-
case 4:
|
|
292
|
-
e_3 = _a.sent();
|
|
293
|
-
console.error(e_3.message);
|
|
294
|
-
process.exit(1);
|
|
295
|
-
return [3 /*break*/, 5];
|
|
296
|
-
case 5: return [2 /*return*/];
|
|
297
|
-
}
|
|
298
|
-
});
|
|
299
|
-
});
|
|
300
|
-
},
|
|
301
|
-
})
|
|
302
|
-
.example("$0 generate-code", "generate code from YAMLs")
|
|
303
|
-
.example("$0 generate-code --language typescript --out-dir ./src", "")
|
|
304
|
-
/**
|
|
305
|
-
* Find duplicate segments
|
|
306
|
-
*/
|
|
307
|
-
.command({
|
|
308
|
-
command: "find-duplicate-segments",
|
|
309
|
-
handler: function (options) {
|
|
310
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
311
|
-
var deps, e_4;
|
|
312
|
-
return __generator(this, function (_a) {
|
|
313
|
-
switch (_a.label) {
|
|
314
|
-
case 0: return [4 /*yield*/, getDependencies(options)];
|
|
315
|
-
case 1:
|
|
316
|
-
deps = _a.sent();
|
|
317
|
-
_a.label = 2;
|
|
318
|
-
case 2:
|
|
319
|
-
_a.trys.push([2, 4, , 5]);
|
|
320
|
-
return [4 /*yield*/, (0, core_1.findDuplicateSegmentsInProject)(deps, {
|
|
321
|
-
authors: options.authors,
|
|
322
|
-
})];
|
|
323
|
-
case 3:
|
|
324
|
-
_a.sent();
|
|
325
|
-
return [3 /*break*/, 5];
|
|
326
|
-
case 4:
|
|
327
|
-
e_4 = _a.sent();
|
|
328
|
-
console.error(e_4.message);
|
|
329
|
-
process.exit(1);
|
|
330
|
-
return [3 /*break*/, 5];
|
|
331
|
-
case 5: return [2 /*return*/];
|
|
332
|
-
}
|
|
333
|
-
});
|
|
334
|
-
});
|
|
335
|
-
},
|
|
336
|
-
})
|
|
337
|
-
.example("$0 find-duplicate-segments", "list segments with same conditions")
|
|
338
|
-
.example("$0 find-duplicate-segments --authors", "show the duplicates along with author names")
|
|
339
|
-
/**
|
|
340
|
-
* Find usage
|
|
341
|
-
*/
|
|
342
|
-
.command({
|
|
343
|
-
command: "find-usage",
|
|
344
|
-
handler: function (options) {
|
|
345
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
346
|
-
var deps, e_5;
|
|
347
|
-
return __generator(this, function (_a) {
|
|
348
|
-
switch (_a.label) {
|
|
349
|
-
case 0: return [4 /*yield*/, getDependencies(options)];
|
|
350
|
-
case 1:
|
|
351
|
-
deps = _a.sent();
|
|
352
|
-
_a.label = 2;
|
|
353
|
-
case 2:
|
|
354
|
-
_a.trys.push([2, 4, , 5]);
|
|
355
|
-
return [4 /*yield*/, (0, core_1.findUsageInProject)(deps, {
|
|
356
|
-
segment: options.segment,
|
|
357
|
-
attribute: options.attribute,
|
|
358
|
-
unusedSegments: options.unusedSegments,
|
|
359
|
-
unusedAttributes: options.unusedAttributes,
|
|
360
|
-
authors: options.authors,
|
|
361
|
-
})];
|
|
362
|
-
case 3:
|
|
363
|
-
_a.sent();
|
|
364
|
-
return [3 /*break*/, 5];
|
|
365
|
-
case 4:
|
|
366
|
-
e_5 = _a.sent();
|
|
367
|
-
console.error(e_5.message);
|
|
368
|
-
process.exit(1);
|
|
369
|
-
return [3 /*break*/, 5];
|
|
370
|
-
case 5: return [2 /*return*/];
|
|
371
|
-
}
|
|
372
|
-
});
|
|
373
|
-
});
|
|
374
|
-
},
|
|
375
|
-
})
|
|
376
|
-
.example("$0 find-usage", "find usage of segments and attributes")
|
|
377
|
-
.example("$0 find-usage --segment=my_segment", "find usage of segment")
|
|
378
|
-
.example("$0 find-usage --attribute=my_attribute", "find usage of attribute")
|
|
379
|
-
.example("$0 find-usage --unusedSegments", "find unused segments")
|
|
380
|
-
.example("$0 find-usage --unusedAttributes", "find unused attributes")
|
|
381
|
-
/**
|
|
382
|
-
* Benchmark features
|
|
383
|
-
*/
|
|
384
|
-
.command({
|
|
385
|
-
command: "benchmark",
|
|
386
|
-
handler: function (options) {
|
|
387
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
388
|
-
var deps, e_6;
|
|
389
|
-
return __generator(this, function (_a) {
|
|
390
|
-
switch (_a.label) {
|
|
391
|
-
case 0:
|
|
392
|
-
if (!options.environment) {
|
|
393
|
-
console.error("Please specify an environment with --environment flag.");
|
|
394
|
-
process.exit(1);
|
|
395
|
-
}
|
|
396
|
-
if (!options.feature) {
|
|
397
|
-
console.error("Please specify a feature with --feature flag.");
|
|
398
|
-
process.exit(1);
|
|
399
|
-
}
|
|
400
|
-
return [4 /*yield*/, getDependencies(options)];
|
|
401
|
-
case 1:
|
|
402
|
-
deps = _a.sent();
|
|
403
|
-
_a.label = 2;
|
|
404
|
-
case 2:
|
|
405
|
-
_a.trys.push([2, 4, , 5]);
|
|
406
|
-
return [4 /*yield*/, (0, core_1.benchmarkFeature)(deps, {
|
|
407
|
-
environment: options.environment,
|
|
408
|
-
feature: options.feature,
|
|
409
|
-
n: parseInt(options.n, 10) || 1,
|
|
410
|
-
context: options.context ? JSON.parse(options.context) : {},
|
|
411
|
-
variation: options.variation || undefined,
|
|
412
|
-
variable: options.variable || undefined,
|
|
413
|
-
})];
|
|
414
|
-
case 3:
|
|
415
|
-
_a.sent();
|
|
416
|
-
return [3 /*break*/, 5];
|
|
417
|
-
case 4:
|
|
418
|
-
e_6 = _a.sent();
|
|
419
|
-
console.error(e_6.message);
|
|
420
|
-
process.exit(1);
|
|
421
|
-
return [3 /*break*/, 5];
|
|
422
|
-
case 5: return [2 /*return*/];
|
|
423
|
-
}
|
|
424
|
-
});
|
|
425
|
-
});
|
|
426
|
-
},
|
|
427
|
-
})
|
|
428
|
-
.example("$0 benchmark", "benchmark feature evaluations")
|
|
429
|
-
.example("$0 benchmark --environment=production --feature=my_feature --context='{}' -n=100", "benchmark feature flag evaluation")
|
|
430
|
-
.example("$0 benchmark --environment=production --feature=my_feature --context='{}' --variation -n=100", "benchmark feature variation evaluation")
|
|
431
|
-
.example("$0 benchmark --environment=production --feature=my_feature --context='{}' --variable=my_variable_key -n=100", "benchmark feature variable evaluation")
|
|
432
|
-
/**
|
|
433
|
-
* Show config
|
|
434
|
-
*/
|
|
435
|
-
.command({
|
|
436
|
-
command: "config",
|
|
437
|
-
handler: function (options) {
|
|
438
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
439
|
-
var projectConfig;
|
|
440
|
-
return __generator(this, function (_a) {
|
|
441
|
-
projectConfig = requireAndGetProjectConfig(rootDirectoryPath);
|
|
442
|
-
(0, core_1.showProjectConfig)(projectConfig, {
|
|
443
|
-
print: options.print,
|
|
444
|
-
pretty: options.pretty,
|
|
445
|
-
});
|
|
446
|
-
return [2 /*return*/];
|
|
447
|
-
});
|
|
448
|
-
});
|
|
449
|
-
},
|
|
450
|
-
})
|
|
451
|
-
.example("$0 config", "show project configuration")
|
|
452
|
-
.example("$0 config --print", "print project configuration as JSON")
|
|
453
|
-
.example("$0 config --print --pretty", "print project configuration as prettified JSON")
|
|
454
|
-
/**
|
|
455
|
-
* Evaluate
|
|
456
|
-
*/
|
|
457
|
-
.command({
|
|
458
|
-
command: "evaluate",
|
|
459
|
-
handler: function (options) {
|
|
460
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
461
|
-
var deps, e_7;
|
|
462
|
-
return __generator(this, function (_a) {
|
|
463
|
-
switch (_a.label) {
|
|
464
|
-
case 0:
|
|
465
|
-
if (!options.environment) {
|
|
466
|
-
console.error("Please specify an environment with --environment flag.");
|
|
467
|
-
process.exit(1);
|
|
468
|
-
}
|
|
469
|
-
if (!options.feature) {
|
|
470
|
-
console.error("Please specify a feature with --feature flag.");
|
|
471
|
-
process.exit(1);
|
|
472
|
-
}
|
|
473
|
-
return [4 /*yield*/, getDependencies(options)];
|
|
474
|
-
case 1:
|
|
475
|
-
deps = _a.sent();
|
|
476
|
-
_a.label = 2;
|
|
477
|
-
case 2:
|
|
478
|
-
_a.trys.push([2, 4, , 5]);
|
|
479
|
-
return [4 /*yield*/, (0, core_1.evaluateFeature)(deps, {
|
|
480
|
-
environment: options.environment,
|
|
481
|
-
feature: options.feature,
|
|
482
|
-
context: options.context ? JSON.parse(options.context) : {},
|
|
483
|
-
print: options.print,
|
|
484
|
-
pretty: options.pretty,
|
|
485
|
-
verbose: options.verbose,
|
|
486
|
-
})];
|
|
487
|
-
case 3:
|
|
488
|
-
_a.sent();
|
|
489
|
-
return [3 /*break*/, 5];
|
|
490
|
-
case 4:
|
|
491
|
-
e_7 = _a.sent();
|
|
492
|
-
console.error(e_7.message);
|
|
493
|
-
process.exit(1);
|
|
494
|
-
return [3 /*break*/, 5];
|
|
495
|
-
case 5: return [2 /*return*/];
|
|
496
|
-
}
|
|
497
|
-
});
|
|
498
|
-
});
|
|
499
|
-
},
|
|
500
|
-
})
|
|
501
|
-
.example("$0 evaluate", "evaluate a feature along with its variation and variables")
|
|
502
|
-
.example("$0 evaluate --environment=production --feature=my_feature --context='{}'", "evaluate a feature against provided context")
|
|
503
|
-
/**
|
|
504
|
-
* Assess distribution
|
|
505
|
-
*/
|
|
506
|
-
.command({
|
|
507
|
-
command: "assess-distribution",
|
|
508
|
-
handler: function (options) {
|
|
509
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
510
|
-
var deps, e_8;
|
|
511
|
-
return __generator(this, function (_a) {
|
|
512
|
-
switch (_a.label) {
|
|
513
|
-
case 0:
|
|
514
|
-
if (!options.environment) {
|
|
515
|
-
console.error("Please specify an environment with --environment flag.");
|
|
516
|
-
process.exit(1);
|
|
517
|
-
}
|
|
518
|
-
if (!options.feature) {
|
|
519
|
-
console.error("Please specify a feature with --feature flag.");
|
|
520
|
-
process.exit(1);
|
|
521
|
-
}
|
|
522
|
-
return [4 /*yield*/, getDependencies(options)];
|
|
523
|
-
case 1:
|
|
524
|
-
deps = _a.sent();
|
|
525
|
-
_a.label = 2;
|
|
526
|
-
case 2:
|
|
527
|
-
_a.trys.push([2, 4, , 5]);
|
|
528
|
-
return [4 /*yield*/, (0, core_1.assessDistribution)(deps, {
|
|
529
|
-
environment: options.environment,
|
|
530
|
-
feature: options.feature,
|
|
531
|
-
context: options.context ? JSON.parse(options.context) : {},
|
|
532
|
-
populateUuid: Array.isArray(options.populateUuid)
|
|
533
|
-
? options.populateUuid
|
|
534
|
-
: [options.populateUuid].filter(Boolean),
|
|
535
|
-
n: parseInt(options.n, 10) || 1,
|
|
536
|
-
verbose: options.verbose,
|
|
537
|
-
})];
|
|
538
|
-
case 3:
|
|
539
|
-
_a.sent();
|
|
540
|
-
return [3 /*break*/, 5];
|
|
541
|
-
case 4:
|
|
542
|
-
e_8 = _a.sent();
|
|
543
|
-
console.error(e_8.message);
|
|
544
|
-
process.exit(1);
|
|
545
|
-
return [3 /*break*/, 5];
|
|
546
|
-
case 5: return [2 /*return*/];
|
|
547
|
-
}
|
|
548
|
-
});
|
|
549
|
-
});
|
|
550
|
-
},
|
|
551
|
-
})
|
|
552
|
-
.example("$0 assess-distribution", "test traffic distribution of a feature")
|
|
553
|
-
.example("$0 assess-distribution --environment=production --feature=my_feature --context='{}' --populateUuid=userId --n=100", "test traffic distribution a feature against provided context")
|
|
554
|
-
/**
|
|
555
|
-
* Info
|
|
556
|
-
*/
|
|
557
|
-
.command({
|
|
558
|
-
command: "info",
|
|
559
|
-
handler: function (options) {
|
|
560
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
561
|
-
var deps, e_9;
|
|
562
|
-
return __generator(this, function (_a) {
|
|
563
|
-
switch (_a.label) {
|
|
564
|
-
case 0: return [4 /*yield*/, getDependencies(options)];
|
|
565
|
-
case 1:
|
|
566
|
-
deps = _a.sent();
|
|
567
|
-
_a.label = 2;
|
|
568
|
-
case 2:
|
|
569
|
-
_a.trys.push([2, 4, , 5]);
|
|
570
|
-
return [4 /*yield*/, (0, core_1.showProjectInfo)(deps)];
|
|
571
|
-
case 3:
|
|
572
|
-
_a.sent();
|
|
573
|
-
return [3 /*break*/, 5];
|
|
574
|
-
case 4:
|
|
575
|
-
e_9 = _a.sent();
|
|
576
|
-
console.error(e_9.message);
|
|
577
|
-
process.exit(1);
|
|
578
|
-
return [3 /*break*/, 5];
|
|
579
|
-
case 5: return [2 /*return*/];
|
|
580
|
-
}
|
|
581
|
-
});
|
|
582
|
-
});
|
|
583
|
-
},
|
|
584
|
-
})
|
|
585
|
-
/**
|
|
586
|
-
* Options
|
|
587
|
-
*/
|
|
588
|
-
// @TODO: add --config option
|
|
589
|
-
/**
|
|
590
|
-
* Help
|
|
591
|
-
*/
|
|
592
|
-
.command({
|
|
593
|
-
command: "*",
|
|
594
|
-
handler: function () {
|
|
595
|
-
yargs.showHelp();
|
|
596
|
-
},
|
|
597
|
-
}).argv;
|
|
598
|
-
return [2 /*return*/];
|
|
50
|
+
switch (_a.label) {
|
|
51
|
+
case 0:
|
|
52
|
+
rootDirectoryPath = process.cwd();
|
|
53
|
+
argv = process.argv.slice(2);
|
|
54
|
+
if (argv.length === 1 && ["version", "--version", "-v"].indexOf(argv[0]) > -1) {
|
|
55
|
+
cliPackage = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf8"));
|
|
56
|
+
corePackage = JSON.parse(fs.readFileSync(require.resolve("@featurevisor/core/package.json"), "utf8"));
|
|
57
|
+
console.log("\nPackage versions:\n");
|
|
58
|
+
console.log(" - @featurevisor/cli: ".concat(cliPackage.version));
|
|
59
|
+
console.log(" - @featurevisor/core: ".concat(corePackage.version));
|
|
60
|
+
return [2 /*return*/];
|
|
61
|
+
}
|
|
62
|
+
useRootDirectoryPath = rootDirectoryPath;
|
|
63
|
+
customRootDir = argv.slice(2).filter(function (arg) { return arg.startsWith("--rootDirectoryPath="); });
|
|
64
|
+
if (customRootDir.length > 0) {
|
|
65
|
+
useRootDirectoryPath = customRootDir[0].split("=")[1];
|
|
66
|
+
}
|
|
67
|
+
configModulePath = path.join(rootDirectoryPath, core_1.CONFIG_MODULE_NAME);
|
|
68
|
+
if (!!fs.existsSync(configModulePath)) return [3 /*break*/, 2];
|
|
69
|
+
// not an existing project
|
|
70
|
+
return [4 /*yield*/, (0, core_1.runCLI)({ rootDirectoryPath: useRootDirectoryPath })];
|
|
71
|
+
case 1:
|
|
72
|
+
// not an existing project
|
|
73
|
+
_a.sent();
|
|
74
|
+
return [3 /*break*/, 4];
|
|
75
|
+
case 2:
|
|
76
|
+
projectConfig = (0, core_1.getProjectConfig)(useRootDirectoryPath);
|
|
77
|
+
datasource = new core_1.Datasource(projectConfig, useRootDirectoryPath);
|
|
78
|
+
return [4 /*yield*/, (0, core_1.runCLI)({
|
|
79
|
+
rootDirectoryPath: useRootDirectoryPath,
|
|
80
|
+
projectConfig: projectConfig,
|
|
81
|
+
datasource: datasource,
|
|
82
|
+
})];
|
|
83
|
+
case 3:
|
|
84
|
+
_a.sent();
|
|
85
|
+
_a.label = 4;
|
|
86
|
+
case 4: return [2 /*return*/];
|
|
87
|
+
}
|
|
599
88
|
});
|
|
600
89
|
});
|
|
601
90
|
}
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uBAAyB;AACzB,2BAA6B;AAE7B,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uBAAyB;AACzB,2BAA6B;AAE7B,2CAA8F;AAE9F,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,UAAC,MAAM;IACtC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACtB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,SAAe,IAAI;;;;;;oBACX,iBAAiB,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;oBAClC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;oBAEnC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;wBACvE,UAAU,GAAG,IAAI,CAAC,KAAK,CAC3B,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CACpE,CAAC;wBAEI,WAAW,GAAG,IAAI,CAAC,KAAK,CAC5B,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,iCAAiC,CAAC,EAAE,MAAM,CAAC,CAC5E,CAAC;wBAEF,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;wBACrC,OAAO,CAAC,GAAG,CAAC,kCAA2B,UAAU,CAAC,OAAO,CAAE,CAAC,CAAC;wBAC7D,OAAO,CAAC,GAAG,CAAC,kCAA2B,WAAW,CAAC,OAAO,CAAE,CAAC,CAAC;wBAE9D,sBAAO;qBACR;oBAEG,oBAAoB,GAAG,iBAAiB,CAAC;oBACvC,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAC,GAAG,IAAK,OAAA,GAAG,CAAC,UAAU,CAAC,sBAAsB,CAAC,EAAtC,CAAsC,CAAC,CAAC;oBAC5F,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE;wBAC5B,oBAAoB,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;qBACvD;oBAEK,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,yBAAkB,CAAC,CAAC;yBACtE,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAhC,wBAAgC;oBAClC,0BAA0B;oBAC1B,qBAAM,IAAA,aAAM,EAAC,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,CAAC,EAAA;;oBADzD,0BAA0B;oBAC1B,SAAyD,CAAC;;;oBAGpD,aAAa,GAAG,IAAA,uBAAgB,EAAC,oBAAoB,CAAC,CAAC;oBACvD,UAAU,GAAG,IAAI,iBAAU,CAAC,aAAa,EAAE,oBAAoB,CAAC,CAAC;oBAEvE,qBAAM,IAAA,aAAM,EAAC;4BACX,iBAAiB,EAAE,oBAAoB;4BACvC,aAAa,eAAA;4BACb,UAAU,YAAA;yBACX,CAAC,EAAA;;oBAJF,SAIE,CAAC;;;;;;CAEN;AAED,IAAI,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@featurevisor/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.27.0",
|
|
4
4
|
"description": "CLI package of Featurevisor",
|
|
5
5
|
"main": "bin.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -47,11 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"license": "MIT",
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@featurevisor/core": "^1.
|
|
51
|
-
"yargs": "^17.6.2"
|
|
50
|
+
"@featurevisor/core": "^1.27.0"
|
|
52
51
|
},
|
|
53
|
-
"
|
|
54
|
-
"@types/yargs": "^17.0.22"
|
|
55
|
-
},
|
|
56
|
-
"gitHead": "4ba871333e577b6164af64e9d66955306fb0fc04"
|
|
52
|
+
"gitHead": "8b06b8f1bb33dd9a80988c013c91381c06c3b606"
|
|
57
53
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,457 +1,54 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
CONFIG_MODULE_NAME,
|
|
6
|
-
getProjectConfig,
|
|
7
|
-
lintProject,
|
|
8
|
-
testProject,
|
|
9
|
-
buildProject,
|
|
10
|
-
initProject,
|
|
11
|
-
exportSite,
|
|
12
|
-
serveSite,
|
|
13
|
-
generateCodeForProject,
|
|
14
|
-
findDuplicateSegmentsInProject,
|
|
15
|
-
findUsageInProject,
|
|
16
|
-
BuildCLIOptions,
|
|
17
|
-
GenerateCodeCLIOptions,
|
|
18
|
-
TestProjectOptions,
|
|
19
|
-
LintProjectOptions,
|
|
20
|
-
restoreProject,
|
|
21
|
-
Dependencies,
|
|
22
|
-
Datasource,
|
|
23
|
-
benchmarkFeature,
|
|
24
|
-
showProjectConfig,
|
|
25
|
-
evaluateFeature,
|
|
26
|
-
assessDistribution,
|
|
27
|
-
showProjectInfo,
|
|
28
|
-
} from "@featurevisor/core";
|
|
29
|
-
|
|
30
|
-
const yargs = require("yargs"); // eslint-disable-line @typescript-eslint/no-var-requires
|
|
4
|
+
import { CONFIG_MODULE_NAME, getProjectConfig, Datasource, runCLI } from "@featurevisor/core";
|
|
31
5
|
|
|
32
6
|
process.on("unhandledRejection", (reason) => {
|
|
33
7
|
console.error(reason);
|
|
34
8
|
process.exit(1);
|
|
35
9
|
});
|
|
36
10
|
|
|
37
|
-
function requireConfigFile(configModulePath) {
|
|
38
|
-
if (!fs.existsSync(configModulePath)) {
|
|
39
|
-
console.error("No config file found. Please create `featurevisor.config.js` file first.");
|
|
40
|
-
|
|
41
|
-
process.exit(1);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function requireAndGetProjectConfig(rootDirectoryPath) {
|
|
46
|
-
const configModulePath = path.join(rootDirectoryPath, CONFIG_MODULE_NAME);
|
|
47
|
-
|
|
48
|
-
requireConfigFile(configModulePath);
|
|
49
|
-
|
|
50
|
-
return getProjectConfig(rootDirectoryPath);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const rootDirectoryPath = process.cwd();
|
|
54
|
-
|
|
55
|
-
async function getDependencies(options): Promise<Dependencies> {
|
|
56
|
-
const useRootDirectoryPath = options.rootDirectoryPath || rootDirectoryPath;
|
|
57
|
-
|
|
58
|
-
const projectConfig = requireAndGetProjectConfig(useRootDirectoryPath);
|
|
59
|
-
const datasource = new Datasource(projectConfig, useRootDirectoryPath);
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
rootDirectoryPath: useRootDirectoryPath,
|
|
63
|
-
projectConfig,
|
|
64
|
-
datasource,
|
|
65
|
-
options,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
|
|
69
11
|
async function main() {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Init
|
|
75
|
-
*/
|
|
76
|
-
.command({
|
|
77
|
-
command: "init",
|
|
78
|
-
handler: async function (options) {
|
|
79
|
-
const hasError = await initProject(rootDirectoryPath, options.example);
|
|
80
|
-
|
|
81
|
-
if (hasError) {
|
|
82
|
-
process.exit(1);
|
|
83
|
-
}
|
|
84
|
-
},
|
|
85
|
-
})
|
|
86
|
-
.example("$0 init", "scaffold a new project")
|
|
87
|
-
.example("$0 init --example=exampleName", "scaffold a new project from known example")
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Lint
|
|
91
|
-
*/
|
|
92
|
-
.command({
|
|
93
|
-
command: "lint",
|
|
94
|
-
handler: async function (options) {
|
|
95
|
-
const deps = await getDependencies(options);
|
|
96
|
-
const lintOptions: LintProjectOptions = {
|
|
97
|
-
keyPattern: options.keyPattern,
|
|
98
|
-
entityType: options.entityType,
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const hasError = await lintProject(deps, lintOptions);
|
|
102
|
-
|
|
103
|
-
if (hasError) {
|
|
104
|
-
process.exit(1);
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
|
-
})
|
|
108
|
-
.example("$0 lint", "lint all YAML file content")
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Build
|
|
112
|
-
*/
|
|
113
|
-
.command({
|
|
114
|
-
command: "build",
|
|
115
|
-
handler: async function (options) {
|
|
116
|
-
const deps = await getDependencies(options);
|
|
117
|
-
|
|
118
|
-
try {
|
|
119
|
-
await buildProject(deps, options as BuildCLIOptions);
|
|
120
|
-
} catch (e) {
|
|
121
|
-
console.error(e);
|
|
122
|
-
process.exit(1);
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
})
|
|
126
|
-
.example("$0 build", "build datafiles")
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Restore
|
|
130
|
-
*/
|
|
131
|
-
.command({
|
|
132
|
-
command: "restore",
|
|
133
|
-
handler: async function (options) {
|
|
134
|
-
const deps = await getDependencies(options);
|
|
135
|
-
|
|
136
|
-
try {
|
|
137
|
-
await restoreProject(deps);
|
|
138
|
-
} catch (e) {
|
|
139
|
-
console.error(e.message);
|
|
140
|
-
process.exit(1);
|
|
141
|
-
}
|
|
142
|
-
},
|
|
143
|
-
})
|
|
144
|
-
.example("$0 restore", "restore state files")
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Test
|
|
148
|
-
*/
|
|
149
|
-
.command({
|
|
150
|
-
command: "test",
|
|
151
|
-
handler: async function (options) {
|
|
152
|
-
const deps = await getDependencies(options);
|
|
153
|
-
|
|
154
|
-
const testOptions: TestProjectOptions = {
|
|
155
|
-
keyPattern: options.keyPattern,
|
|
156
|
-
assertionPattern: options.assertionPattern,
|
|
157
|
-
verbose: options.verbose || false,
|
|
158
|
-
showDatafile: options.showDatafile || false,
|
|
159
|
-
onlyFailures: options.onlyFailures || false,
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
const hasError = await testProject(deps, testOptions);
|
|
163
|
-
|
|
164
|
-
if (hasError) {
|
|
165
|
-
process.exit(1);
|
|
166
|
-
}
|
|
167
|
-
},
|
|
168
|
-
})
|
|
169
|
-
.example("$0 test", "test features")
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Site
|
|
173
|
-
*/
|
|
174
|
-
.command({
|
|
175
|
-
command: "site [subcommand]",
|
|
176
|
-
handler: async function (options) {
|
|
177
|
-
const deps = await getDependencies(options);
|
|
178
|
-
|
|
179
|
-
const allowedSubcommands = ["export", "serve"];
|
|
180
|
-
|
|
181
|
-
if (!allowedSubcommands.includes(options.subcommand)) {
|
|
182
|
-
console.log("Please specify a subcommand: `export` or `serve`");
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
12
|
+
const rootDirectoryPath = process.cwd();
|
|
13
|
+
const argv = process.argv.slice(2);
|
|
185
14
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
15
|
+
if (argv.length === 1 && ["version", "--version", "-v"].indexOf(argv[0]) > -1) {
|
|
16
|
+
const cliPackage = JSON.parse(
|
|
17
|
+
fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf8"),
|
|
18
|
+
);
|
|
189
19
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
20
|
+
const corePackage = JSON.parse(
|
|
21
|
+
fs.readFileSync(require.resolve("@featurevisor/core/package.json"), "utf8"),
|
|
22
|
+
);
|
|
194
23
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
},
|
|
200
|
-
})
|
|
201
|
-
.example("$0 site export", "generate static site with project data")
|
|
202
|
-
.example("$0 site serve", "serve already exported site locally")
|
|
203
|
-
.example("$0 site serve -p 3000", "serve in a specific port")
|
|
24
|
+
console.log("\nPackage versions:\n");
|
|
25
|
+
console.log(` - @featurevisor/cli: ${cliPackage.version}`);
|
|
26
|
+
console.log(` - @featurevisor/core: ${corePackage.version}`);
|
|
204
27
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
*/
|
|
208
|
-
.command({
|
|
209
|
-
command: "generate-code",
|
|
210
|
-
handler: async function (options) {
|
|
211
|
-
const deps = await getDependencies(options);
|
|
212
|
-
|
|
213
|
-
try {
|
|
214
|
-
await generateCodeForProject(deps, options as unknown as GenerateCodeCLIOptions);
|
|
215
|
-
} catch (e) {
|
|
216
|
-
console.error(e.message);
|
|
217
|
-
process.exit(1);
|
|
218
|
-
}
|
|
219
|
-
},
|
|
220
|
-
})
|
|
221
|
-
.example("$0 generate-code", "generate code from YAMLs")
|
|
222
|
-
.example("$0 generate-code --language typescript --out-dir ./src", "")
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Find duplicate segments
|
|
226
|
-
*/
|
|
227
|
-
.command({
|
|
228
|
-
command: "find-duplicate-segments",
|
|
229
|
-
handler: async function (options) {
|
|
230
|
-
const deps = await getDependencies(options);
|
|
231
|
-
|
|
232
|
-
try {
|
|
233
|
-
await findDuplicateSegmentsInProject(deps, {
|
|
234
|
-
authors: options.authors,
|
|
235
|
-
});
|
|
236
|
-
} catch (e) {
|
|
237
|
-
console.error(e.message);
|
|
238
|
-
process.exit(1);
|
|
239
|
-
}
|
|
240
|
-
},
|
|
241
|
-
})
|
|
242
|
-
.example("$0 find-duplicate-segments", "list segments with same conditions")
|
|
243
|
-
.example("$0 find-duplicate-segments --authors", "show the duplicates along with author names")
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Find usage
|
|
247
|
-
*/
|
|
248
|
-
.command({
|
|
249
|
-
command: "find-usage",
|
|
250
|
-
handler: async function (options) {
|
|
251
|
-
const deps = await getDependencies(options);
|
|
252
|
-
|
|
253
|
-
try {
|
|
254
|
-
await findUsageInProject(deps, {
|
|
255
|
-
segment: options.segment,
|
|
256
|
-
attribute: options.attribute,
|
|
257
|
-
|
|
258
|
-
unusedSegments: options.unusedSegments,
|
|
259
|
-
unusedAttributes: options.unusedAttributes,
|
|
260
|
-
|
|
261
|
-
authors: options.authors,
|
|
262
|
-
});
|
|
263
|
-
} catch (e) {
|
|
264
|
-
console.error(e.message);
|
|
265
|
-
process.exit(1);
|
|
266
|
-
}
|
|
267
|
-
},
|
|
268
|
-
})
|
|
269
|
-
.example("$0 find-usage", "find usage of segments and attributes")
|
|
270
|
-
.example("$0 find-usage --segment=my_segment", "find usage of segment")
|
|
271
|
-
.example("$0 find-usage --attribute=my_attribute", "find usage of attribute")
|
|
272
|
-
.example("$0 find-usage --unusedSegments", "find unused segments")
|
|
273
|
-
.example("$0 find-usage --unusedAttributes", "find unused attributes")
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Benchmark features
|
|
277
|
-
*/
|
|
278
|
-
.command({
|
|
279
|
-
command: "benchmark",
|
|
280
|
-
handler: async function (options) {
|
|
281
|
-
if (!options.environment) {
|
|
282
|
-
console.error("Please specify an environment with --environment flag.");
|
|
283
|
-
process.exit(1);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
if (!options.feature) {
|
|
287
|
-
console.error("Please specify a feature with --feature flag.");
|
|
288
|
-
process.exit(1);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
const deps = await getDependencies(options);
|
|
292
|
-
|
|
293
|
-
try {
|
|
294
|
-
await benchmarkFeature(deps, {
|
|
295
|
-
environment: options.environment,
|
|
296
|
-
feature: options.feature,
|
|
297
|
-
n: parseInt(options.n, 10) || 1,
|
|
298
|
-
context: options.context ? JSON.parse(options.context) : {},
|
|
299
|
-
variation: options.variation || undefined,
|
|
300
|
-
variable: options.variable || undefined,
|
|
301
|
-
});
|
|
302
|
-
} catch (e) {
|
|
303
|
-
console.error(e.message);
|
|
304
|
-
process.exit(1);
|
|
305
|
-
}
|
|
306
|
-
},
|
|
307
|
-
})
|
|
308
|
-
.example("$0 benchmark", "benchmark feature evaluations")
|
|
309
|
-
.example(
|
|
310
|
-
"$0 benchmark --environment=production --feature=my_feature --context='{}' -n=100",
|
|
311
|
-
"benchmark feature flag evaluation",
|
|
312
|
-
)
|
|
313
|
-
.example(
|
|
314
|
-
"$0 benchmark --environment=production --feature=my_feature --context='{}' --variation -n=100",
|
|
315
|
-
"benchmark feature variation evaluation",
|
|
316
|
-
)
|
|
317
|
-
.example(
|
|
318
|
-
"$0 benchmark --environment=production --feature=my_feature --context='{}' --variable=my_variable_key -n=100",
|
|
319
|
-
"benchmark feature variable evaluation",
|
|
320
|
-
)
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* Show config
|
|
324
|
-
*/
|
|
325
|
-
.command({
|
|
326
|
-
command: "config",
|
|
327
|
-
handler: async function (options) {
|
|
328
|
-
const projectConfig = requireAndGetProjectConfig(rootDirectoryPath);
|
|
329
|
-
|
|
330
|
-
showProjectConfig(projectConfig, {
|
|
331
|
-
print: options.print,
|
|
332
|
-
pretty: options.pretty,
|
|
333
|
-
});
|
|
334
|
-
},
|
|
335
|
-
})
|
|
336
|
-
.example("$0 config", "show project configuration")
|
|
337
|
-
.example("$0 config --print", "print project configuration as JSON")
|
|
338
|
-
.example("$0 config --print --pretty", "print project configuration as prettified JSON")
|
|
339
|
-
|
|
340
|
-
/**
|
|
341
|
-
* Evaluate
|
|
342
|
-
*/
|
|
343
|
-
.command({
|
|
344
|
-
command: "evaluate",
|
|
345
|
-
handler: async function (options) {
|
|
346
|
-
if (!options.environment) {
|
|
347
|
-
console.error("Please specify an environment with --environment flag.");
|
|
348
|
-
process.exit(1);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
if (!options.feature) {
|
|
352
|
-
console.error("Please specify a feature with --feature flag.");
|
|
353
|
-
process.exit(1);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
const deps = await getDependencies(options);
|
|
357
|
-
|
|
358
|
-
try {
|
|
359
|
-
await evaluateFeature(deps, {
|
|
360
|
-
environment: options.environment,
|
|
361
|
-
feature: options.feature,
|
|
362
|
-
context: options.context ? JSON.parse(options.context) : {},
|
|
363
|
-
print: options.print,
|
|
364
|
-
pretty: options.pretty,
|
|
365
|
-
verbose: options.verbose,
|
|
366
|
-
});
|
|
367
|
-
} catch (e) {
|
|
368
|
-
console.error(e.message);
|
|
369
|
-
process.exit(1);
|
|
370
|
-
}
|
|
371
|
-
},
|
|
372
|
-
})
|
|
373
|
-
.example("$0 evaluate", "evaluate a feature along with its variation and variables")
|
|
374
|
-
.example(
|
|
375
|
-
"$0 evaluate --environment=production --feature=my_feature --context='{}'",
|
|
376
|
-
"evaluate a feature against provided context",
|
|
377
|
-
)
|
|
378
|
-
|
|
379
|
-
/**
|
|
380
|
-
* Assess distribution
|
|
381
|
-
*/
|
|
382
|
-
.command({
|
|
383
|
-
command: "assess-distribution",
|
|
384
|
-
handler: async function (options) {
|
|
385
|
-
if (!options.environment) {
|
|
386
|
-
console.error("Please specify an environment with --environment flag.");
|
|
387
|
-
process.exit(1);
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
if (!options.feature) {
|
|
391
|
-
console.error("Please specify a feature with --feature flag.");
|
|
392
|
-
process.exit(1);
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
const deps = await getDependencies(options);
|
|
396
|
-
|
|
397
|
-
try {
|
|
398
|
-
await assessDistribution(deps, {
|
|
399
|
-
environment: options.environment,
|
|
400
|
-
feature: options.feature,
|
|
401
|
-
context: options.context ? JSON.parse(options.context) : {},
|
|
402
|
-
populateUuid: Array.isArray(options.populateUuid)
|
|
403
|
-
? options.populateUuid
|
|
404
|
-
: [options.populateUuid as string].filter(Boolean),
|
|
405
|
-
n: parseInt(options.n, 10) || 1,
|
|
406
|
-
verbose: options.verbose,
|
|
407
|
-
});
|
|
408
|
-
} catch (e) {
|
|
409
|
-
console.error(e.message);
|
|
410
|
-
process.exit(1);
|
|
411
|
-
}
|
|
412
|
-
},
|
|
413
|
-
})
|
|
414
|
-
.example("$0 assess-distribution", "test traffic distribution of a feature")
|
|
415
|
-
.example(
|
|
416
|
-
"$0 assess-distribution --environment=production --feature=my_feature --context='{}' --populateUuid=userId --n=100",
|
|
417
|
-
"test traffic distribution a feature against provided context",
|
|
418
|
-
)
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* Info
|
|
422
|
-
*/
|
|
423
|
-
.command({
|
|
424
|
-
command: "info",
|
|
425
|
-
handler: async function (options) {
|
|
426
|
-
const deps = await getDependencies(options);
|
|
427
|
-
|
|
428
|
-
try {
|
|
429
|
-
await showProjectInfo(deps);
|
|
430
|
-
} catch (e) {
|
|
431
|
-
console.error(e.message);
|
|
432
|
-
process.exit(1);
|
|
433
|
-
}
|
|
434
|
-
},
|
|
435
|
-
})
|
|
436
|
-
|
|
437
|
-
/**
|
|
438
|
-
* Options
|
|
439
|
-
*/
|
|
440
|
-
|
|
441
|
-
// @TODO: add --config option
|
|
442
|
-
|
|
443
|
-
/**
|
|
444
|
-
* Help
|
|
445
|
-
*/
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
446
30
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
}).argv;
|
|
31
|
+
let useRootDirectoryPath = rootDirectoryPath;
|
|
32
|
+
const customRootDir = argv.slice(2).filter((arg) => arg.startsWith("--rootDirectoryPath="));
|
|
33
|
+
if (customRootDir.length > 0) {
|
|
34
|
+
useRootDirectoryPath = customRootDir[0].split("=")[1];
|
|
35
|
+
}
|
|
453
36
|
|
|
454
|
-
|
|
37
|
+
const configModulePath = path.join(rootDirectoryPath, CONFIG_MODULE_NAME);
|
|
38
|
+
if (!fs.existsSync(configModulePath)) {
|
|
39
|
+
// not an existing project
|
|
40
|
+
await runCLI({ rootDirectoryPath: useRootDirectoryPath });
|
|
41
|
+
} else {
|
|
42
|
+
// existing project
|
|
43
|
+
const projectConfig = getProjectConfig(useRootDirectoryPath);
|
|
44
|
+
const datasource = new Datasource(projectConfig, useRootDirectoryPath);
|
|
45
|
+
|
|
46
|
+
await runCLI({
|
|
47
|
+
rootDirectoryPath: useRootDirectoryPath,
|
|
48
|
+
projectConfig,
|
|
49
|
+
datasource,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
455
52
|
}
|
|
456
53
|
|
|
457
54
|
main();
|