UNPKG

96.5 kBJavaScriptView Raw
1#!/usr/bin/env node
2/*----------------------------------------------
3 * Generated by rollup. Written by John Schmidt.
4 * Rally Tools CLI v1.11.13
5 *--------------------------------------------*/
6const importLazy = require("import-lazy")(require);
7
8'use strict';
9
10function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
11
12var argparse = _interopDefault(require('minimist'));
13var chalk$1 = _interopDefault(require('chalk'));
14var os = require('os');
15var fs = require('fs');
16var fs__default = _interopDefault(fs);
17var child_process = require('child_process');
18var perf_hooks = require('perf_hooks');
19var path = require('path');
20var path__default = _interopDefault(path);
21var moment = _interopDefault(require('moment'));
22
23function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
24 var desc = {};
25 Object['ke' + 'ys'](descriptor).forEach(function (key) {
26 desc[key] = descriptor[key];
27 });
28 desc.enumerable = !!desc.enumerable;
29 desc.configurable = !!desc.configurable;
30
31 if ('value' in desc || desc.initializer) {
32 desc.writable = true;
33 }
34
35 desc = decorators.slice().reverse().reduce(function (desc, decorator) {
36 return decorator(target, property, desc) || desc;
37 }, desc);
38
39 if (context && desc.initializer !== void 0) {
40 desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
41 desc.initializer = undefined;
42 }
43
44 if (desc.initializer === void 0) {
45 Object['define' + 'Property'](target, property, desc);
46 desc = null;
47 }
48
49 return desc;
50}
51
52let configFile = os.homedir() + "/.rallyconfig";
53let configObject;
54function loadConfig(file) {
55 if (file) configFile = file;
56 configObject = {
57 hasConfig: true
58 };
59
60 try {
61 let json = fs.readFileSync(configFile);
62 configObject = JSON.parse(json);
63 configObject.hasConfig = true;
64 } catch (e) {
65 if (e.code == "ENOENT") {
66 configObject.hasConfig = false; //ok, they should probably make a config
67 } else {
68 throw e;
69 }
70 }
71}
72function setConfig(obj) {
73 configObject = obj;
74}
75loadConfig();
76
77//these are the help entries for each command
78let helpEntries = {};
79
80let helpEntry = name => helpEntries[name] ? helpEntries[name] : helpEntries[name] = {
81 name
82}; //short description
83
84
85function helpText(text) {
86 return function (func, name) {
87 helpEntry(name).text = text;
88 return func;
89 };
90} //flag type argument like -f or --file
91
92function arg(long, short, desc) {
93 return function (func, name) {
94 let args = helpEntry(name).args = helpEntry(name).args || [];
95 args.unshift({
96 long,
97 short,
98 desc
99 });
100 return func;
101 };
102} //normal argument
103
104function param(param, desc) {
105 return function (func, name) {
106 let params = helpEntry(name).params = helpEntry(name).params || [];
107 params.unshift({
108 param,
109 desc
110 });
111 return func;
112 };
113} //usage string
114
115function usage(usage) {
116 return function (func, name) {
117 usage = usage.replace(/[\[<](\w+)[\]>]/g, chalk`[{blue $1}]`);
118 helpEntry(name).usage = usage;
119 return func;
120 };
121}
122//function retuns obj.a.b.c
123
124function deepAccess(obj, path$$1) {
125 let o = obj;
126
127 for (let key of path$$1) {
128 if (!o) return [];
129 o = o[key];
130 }
131
132 return o;
133} //This takes a class as the first argument, then adds a getter/setter pair that
134//corresponds to an object in this.data
135
136
137function defineAssoc(classname, shortname, path$$1) {
138 path$$1 = path$$1.split(".");
139 let lastKey = path$$1.pop();
140 Object.defineProperty(classname.prototype, shortname, {
141 get() {
142 return deepAccess(this, path$$1)[lastKey];
143 },
144
145 set(val) {
146 deepAccess(this, path$$1)[lastKey] = val;
147 }
148
149 });
150}
151
152function spawn(options, ...args) {
153 if (typeof options !== "object") {
154 args.unshift(options);
155 options = {};
156 } //todo options
157
158
159 return new Promise((resolve, reject) => {
160 let start = perf_hooks.performance.now();
161 let stdout = "";
162 let stderr = "";
163 let cp = child_process.spawn(...args);
164 if (cp.stdout) cp.stdout.on("data", chunk => {
165 stdout += chunk;
166 write(chunk);
167 });
168 if (cp.stderr) cp.stderr.on("data", chunk => {
169 stderr += chunk;
170 write(chunk);
171 });
172 cp.on("error", reject);
173 cp.on("close", code => {
174 let end = perf_hooks.performance.now();
175 let time = end - start;
176 let timestr = time > 1000 ? (time / 100 | 0) / 10 + "s" : (time | 0) + "ms";
177 resolve({
178 stdout,
179 stderr,
180 exitCode: code,
181 time,
182 timestr
183 });
184 });
185 });
186}
187
188const rp = importLazy("request-promise");
189global.chalk = chalk$1;
190
191global.log = (...text) => console.log(...text);
192
193global.write = (...text) => process.stdout.write(...text);
194
195global.elog = (...text) => console.log(...text);
196
197global.ewrite = (...text) => process.stderr.write(...text);
198
199global.errorLog = (...text) => log(...text.map(chalk$1.red));
200
201class lib {
202 //This function takes 2 required arguemnts:
203 // env: the enviornment you wish to use
204 // and either:
205 // 'path', the short path to the resource. ex '/presets/'
206 // 'path_full', the full path to the resource like 'https://discovery-dev.sdvi.com/presets'
207 //
208 // If the method is anything but GET, either payload or body should be set.
209 // payload should be a javascript object to be turned into json as the request body
210 // body should be a string that is passed as the body. for example: the python code of a preset.
211 //
212 // qs are the querystring parameters, in a key: value object.
213 // {filter: "name=test name"} becomes something like 'filter=name=test+name'
214 //
215 // headers are the headers of the request. "Content-Type" is already set if
216 // payload is given as a parameter
217 //
218 // fullResponse should be true if you want to receive the request object,
219 // not just the returned data.
220 static async makeAPIRequest({
221 env,
222 path: path$$1,
223 path_full,
224 fullPath,
225 payload,
226 body,
227 method = "GET",
228 qs,
229 headers = {},
230 fullResponse = false,
231 timeout = configObject.timeout || 20000
232 }) {
233 var _configObject$api;
234
235 //backwards compatability from ruby script
236 if (fullPath) path_full = fullPath; //Keys are defined in enviornment variables
237
238 let config = configObject === null || configObject === void 0 ? void 0 : (_configObject$api = configObject.api) === null || _configObject$api === void 0 ? void 0 : _configObject$api[env];
239
240 if (!config) {
241 throw new UnconfiguredEnvError(env);
242 }
243
244 if (method !== "GET" && !configObject.dangerModify) {
245 if (env === "UAT" && configObject.restrictUAT || env === "PROD") {
246 throw new ProtectedEnvError(env);
247 }
248 }
249
250 let rally_api_key = config.key;
251 let rally_api = config.url;
252
253 if (path$$1 && path$$1.startsWith("/v1.0/")) {
254 rally_api = rally_api.replace("/api/v2", "/api");
255 }
256
257 path$$1 = path_full || rally_api + path$$1;
258
259 if (payload) {
260 body = JSON.stringify(payload, null, 4);
261 }
262
263 if (payload) {
264 headers["Content-Type"] = "application/vnd.api+json";
265 }
266
267 let fullHeaders = {
268 //SDVI ignores this header sometimes.
269 Accept: "application/vnd.api+json",
270 "X-SDVI-Client-Application": "Discovery-rtlib-" + (configObject.appName || "commandline"),
271 ...headers
272 };
273
274 if (configObject.vvverbose) {
275 log(`${method} @ ${path$$1}`);
276 log(JSON.stringify(fullHeaders, null, 4));
277
278 if (body) {
279 log(body);
280 } else {
281 log("(No body");
282 }
283 }
284
285 let requestOptions = {
286 method,
287 body,
288 qs,
289 uri: path$$1,
290 timeout,
291 auth: {
292 bearer: rally_api_key
293 },
294 headers: fullHeaders,
295 simple: false,
296 resolveWithFullResponse: true
297 };
298 let response;
299
300 try {
301 response = await rp(requestOptions);
302
303 if (configObject.vverbose || configObject.vvverbose) {
304 log(chalk$1`${method} @ ${response.request.uri.href}`);
305 }
306 } catch (e) {
307 if ((e === null || e === void 0 ? void 0 : e.cause.code) === "ESOCKETTIMEDOUT") {
308 throw new APIError(response || {}, requestOptions, body);
309 } else {
310 throw e;
311 }
312 } //Throw an error for any 5xx or 4xx
313
314
315 if (!fullResponse && ![200, 201, 202, 203, 204].includes(response.statusCode)) {
316 throw new APIError(response, requestOptions, body);
317 }
318
319 let contentType = response.headers["content-type"];
320 let isJSONResponse = contentType === "application/vnd.api+json" || contentType === "application/json";
321
322 if (configObject.vvverbose) {
323 log(response.body);
324 }
325
326 if (fullResponse) {
327 return response;
328 } else if (isJSONResponse) {
329 try {
330 return JSON.parse(response.body);
331 } catch (e) {
332 log(response.body);
333 throw new AbortError("Body is not valid json: ");
334 }
335 } else {
336 return response.body;
337 }
338 } //Index a json endpoint that returns a {links} field.
339 //This function returns the merged data objects as an array
340 //
341 //Additonal options (besides makeAPIRequest options):
342 // - Observe: function to be called for each set of data from the api
343
344
345 static async indexPath(env, path$$1) {
346 let all = [];
347 let opts = typeof env === "string" ? {
348 env,
349 path: path$$1
350 } : env;
351 let json = await this.makeAPIRequest(opts);
352 let [numPages, pageSize] = this.numPages(json.links.last); //log(`num pages: ${numPages} * ${pageSize}`);
353
354 all = [...json.data];
355
356 while (json.links.next) {
357 json = await this.makeAPIRequest({ ...opts,
358 path_full: json.links.next
359 });
360 if (opts.observe) await opts.observe(json.data);
361 all = [...all, ...json.data];
362 }
363
364 return all;
365 } //Returns number of pages and pagination size
366
367
368 static numPages(str) {
369 return /page=(\d+)p(\d+)/.exec(str).slice(1);
370 }
371
372 static arrayChunk(array, chunkSize) {
373 let newArr = [];
374
375 for (let i = 0; i < array.length; i += chunkSize) {
376 newArr.push(array.slice(i, i + chunkSize));
377 }
378
379 return newArr;
380 }
381
382 static async doPromises(promises, result = [], cb) {
383 for (let promise of promises) {
384 let res = await promise;
385 result.push(res);
386
387 if (cb) {
388 cb(res.data);
389 }
390 }
391
392 return result;
393 }
394
395 static clearProgress(size = 30) {
396 process.stderr.write(`\r${" ".repeat(size + 15)}\r`);
397 }
398
399 static async drawProgress(i, max, size = process.stdout.columns - 15 || 15) {
400 if (size > 45) size = 45;
401 let pct = Number(i) / Number(max); //clamp between 0 and 1
402
403 pct = pct < 0 ? 0 : pct > 1 ? 1 : pct;
404 let numFilled = Math.floor(pct * size);
405 let numEmpty = size - numFilled;
406 this.clearProgress(size);
407 process.stderr.write(`[${"*".repeat(numFilled)}${" ".repeat(numEmpty)}] ${i} / ${max}`);
408 }
409
410 static async keepalive(func, inputData, {
411 chunksize,
412 observe = async _ => _
413 } = {}) {
414 let total = inputData ? inputData.length : func.length;
415 let i = 0;
416
417 let createPromise = () => {
418 let ret;
419 if (i >= total) return [];
420
421 if (inputData) {
422 ret = [i, func(inputData[i])];
423 } else {
424 ret = [i, func[i]()];
425 }
426
427 i++;
428 return ret;
429 };
430
431 let values = [];
432 let finished = 0;
433 process.stderr.write("\n");
434 let threads = [...this.range(20)].map(async whichThread => {
435 while (true) {
436 let [i, currentPromise] = createPromise();
437 if (i == undefined) break;
438 values[i] = await observe((await currentPromise));
439 this.drawProgress(++finished, total);
440 }
441 });
442 await Promise.all(threads);
443 process.stderr.write("\n");
444 return values;
445 }
446
447 static *range(start, end) {
448 if (end === undefined) {
449 end = start;
450 start = 0;
451 }
452
453 while (start < end) yield start++;
454 } //Index a json endpoint that returns a {links} field.
455 //
456 //This function is faster than indexPath because it can guess the pages it
457 //needs to retreive so that it can request all assets at once.
458 //
459 //This function assumes that the content from the inital request is the
460 //first page, so starting on another page may cause issues. Consider
461 //indexPath for that.
462 //
463 //Additional opts, besides default indexPath opts:
464 // - chunksize[10]: How often to break apart concurrent requests
465
466
467 static async indexPathFast(env, path$$1) {
468 let opts = typeof env === "string" ? {
469 env,
470 path: path$$1
471 } : env; //Create a copy of the options in case we need to have a special first request
472
473 let start = opts.start || 1;
474 let initOpts = { ...opts
475 };
476
477 if (opts.pageSize) {
478 initOpts.qs = { ...opts.qs
479 };
480 initOpts.qs.page = `${start}p${opts.pageSize}`;
481 }
482
483 let json = await this.makeAPIRequest(initOpts);
484 if (opts.observe && opts.start !== 1) json = await opts.observe(json);
485 let baselink = json.links.first;
486
487 const linkToPage = page => baselink.replace(`page=1p`, `page=${page}p`);
488
489 let [numPages, pageSize] = this.numPages(json.links.last); //Construct an array of all the requests that are done simultanously.
490 //Assume that the content from the inital request is the first page.
491
492 let allResults = await this.keepalive(this.makeAPIRequest, [...this.range(start + 1, Number(numPages) + 1 || opts.limit + 1)].map(i => ({ ...opts,
493 path_full: linkToPage(i)
494 })), {
495 chunksize: opts.chunksize,
496 observe: opts.observe
497 });
498
499 if (start == 1) {
500 allResults.unshift(json);
501 }
502
503 this.clearProgress();
504 let all = [];
505
506 for (let result of allResults) {
507 for (let item of result.data) {
508 all.push(item);
509 }
510 }
511
512 return all;
513 }
514
515 static isLocalEnv(env) {
516 return !env || env === "LOCAL" || env === "LOC";
517 }
518
519 static envName(env) {
520 if (this.isLocalEnv(env)) return "LOCAL";
521 return env;
522 }
523
524}
525class AbortError extends Error {
526 constructor(message) {
527 super(message);
528 Error.captureStackTrace(this, this.constructor);
529 this.name = "AbortError";
530 }
531
532}
533class APIError extends Error {
534 constructor(response, opts, body) {
535 super(chalk$1`
536{reset Request returned} {yellow ${response === null || response === void 0 ? void 0 : response.statusCode}}{
537{green ${JSON.stringify(opts, null, 4)}}
538{green ${body}}
539{reset ${response.body}}
540===============================
541{red ${response.body ? "Request timed out" : "Bad response from API"}}
542===============================
543 `);
544 this.response = response;
545 this.opts = opts;
546 this.body = body;
547 Error.captureStackTrace(this, this.constructor);
548 this.name = "ApiError";
549 }
550
551}
552class UnconfiguredEnvError extends AbortError {
553 constructor(env) {
554 super("Unconfigured enviornment: " + env);
555 this.name = "Unconfigured Env Error";
556 }
557
558}
559class ProtectedEnvError extends AbortError {
560 constructor(env) {
561 super("Protected enviornment: " + env);
562 this.name = "Protected Env Error";
563 }
564
565}
566class Collection {
567 constructor(arr) {
568 this.arr = arr;
569 }
570
571 [Symbol.iterator]() {
572 return this.arr[Symbol.iterator]();
573 }
574
575 findById(id) {
576 return this.arr.find(x => x.id == id);
577 }
578
579 findByName(name) {
580 return this.arr.find(x => x.name == name);
581 }
582
583 findByNameContains(name) {
584 return this.arr.find(x => x.name.includes(name));
585 }
586
587 log() {
588 for (let d of this) {
589 if (d) {
590 log(d.chalkPrint(true));
591 } else {
592 log(chalk$1`{red (None)}`);
593 }
594 }
595 }
596
597 get length() {
598 return this.arr.length;
599 }
600
601}
602class RallyBase {
603 static handleCaching() {
604 if (!this.cache) this.cache = [];
605 }
606
607 static isLoaded(env) {
608 if (!this.hasLoadedAll) return;
609 return this.hasLoadedAll[env];
610 }
611
612 static async getById(env, id, qs) {
613 this.handleCaching();
614
615 for (let item of this.cache) {
616 if (item.id == id && item.remote === env || `${env}-${id}` === item.metastring) return item;
617 }
618
619 let data = await lib.makeAPIRequest({
620 env,
621 path: `/${this.endpoint}/${id}`,
622 qs
623 });
624
625 if (data.data) {
626 let o = new this({
627 data: data.data,
628 remote: env,
629 included: data.included
630 });
631 this.cache.push(o);
632 return o;
633 }
634 }
635
636 static async getByName(env, name, qs) {
637 this.handleCaching();
638
639 for (let item of this.cache) {
640 if (item.name === name && item.remote === env) return item;
641 }
642
643 let data = await lib.makeAPIRequest({
644 env,
645 path: `/${this.endpoint}`,
646 qs: { ...qs,
647 filter: `name=${name}` + (qs ? qs.filter : "")
648 }
649 }); //TODO included might not wokr correctly here
650
651 if (data.data[0]) {
652 let o = new this({
653 data: data.data[0],
654 remote: env,
655 included: data.included
656 });
657 this.cache.push(o);
658 return o;
659 }
660 }
661
662 static async getAllPreCollect(d) {
663 return d;
664 }
665
666 static async getAll(env) {
667 this.handleCaching();
668 let datas = await lib.indexPathFast({
669 env,
670 path: `/${this.endpoint}`,
671 pageSize: "50",
672 qs: {
673 sort: "id"
674 }
675 });
676 datas = await this.getAllPreCollect(datas);
677 let all = new Collection(datas.map(data => new this({
678 data,
679 remote: env
680 })));
681 this.cache = [...this.cache, ...all.arr];
682 return all;
683 }
684
685 static async removeCache(env) {
686 this.handleCaching();
687 this.cache = this.cache.filter(x => x.remote !== env);
688 } //Specific turns name into id based on env
689 //Generic turns ids into names
690
691
692 async resolveApply(type, dataObj, direction) {
693 let obj;
694
695 if (direction == "generic") {
696 obj = await type.getById(this.remote, dataObj.id);
697
698 if (obj) {
699 dataObj.name = obj.name;
700 }
701 } else if (direction == "specific") {
702 obj = await type.getByName(this.remote, dataObj.name);
703
704 if (obj) {
705 dataObj.id = obj.id;
706 }
707 }
708
709 return obj;
710 } //Type is the baseclass you are looking for (should extend RallyBase)
711 //name is the name of the field
712 //isArray is true if it has multiple cardinailty, false if it is single
713 //direction gets passed directly to resolveApply
714
715
716 async resolveField(type, name, isArray = false, direction = "generic") {
717 // ignore empty fields
718 let field = this.relationships[name];
719 if (!(field === null || field === void 0 ? void 0 : field.data)) return;
720
721 if (isArray) {
722 return await Promise.all(field.data.map(o => this.resolveApply(type, o, direction)));
723 } else {
724 return await this.resolveApply(type, field.data, direction);
725 }
726 }
727
728 cleanup() {
729 for (let [key, val] of Object.entries(this.relationships)) {
730 //Remove ids from data
731 if (val.data) {
732 if (val.data.id) {
733 delete val.data.id;
734 } else if (val.data[0]) {
735 for (let x of val.data) delete x.id;
736 }
737 }
738
739 delete val.links;
740 } // organization is unused (?)
741
742
743 delete this.relationships.organization; // id is specific to envs
744 // but save source inside meta string in case we need it
745
746 this.metastring = this.remote + "-" + this.data.id;
747 delete this.data.id; // links too
748
749 delete this.data.links;
750 }
751
752}
753
754class Provider extends RallyBase {
755 constructor({
756 data,
757 remote
758 }) {
759 super();
760 this.data = data;
761 this.meta = {};
762 this.remote = remote;
763 } //cached
764
765
766 async getEditorConfig() {
767 if (this.editorConfig) return this.editorConfig;
768 this.editorConfig = await lib.makeAPIRequest({
769 env: this.remote,
770 path_full: this.data.links.editorConfig
771 });
772 this.editorConfig.fileExt = await this.getFileExtension();
773 return this.editorConfig;
774 }
775
776 static async getAllPreCollect(providers) {
777 return providers.sort((a, b) => {
778 return a.attributes.category.localeCompare(b.attributes.category) || a.attributes.name.localeCompare(b.attributes.name);
779 });
780 }
781
782 async getFileExtension() {
783 let config = await this.getEditorConfig();
784 let map = {
785 python: "py",
786 text: "txt",
787
788 getmap(key) {
789 if (this.name === "Aurora") return "zip";
790 if (this[key]) return this[key];
791 return key;
792 }
793
794 };
795 return map.getmap(config.lang);
796 }
797
798 chalkPrint(pad = true) {
799 let id = String(this.id);
800 if (pad) id = id.padStart(4);
801 return chalk`{green ${id}}: {blue ${this.category}} - {green ${this.name}}`;
802 }
803
804}
805
806defineAssoc(Provider, "id", "data.id");
807defineAssoc(Provider, "name", "data.attributes.name");
808defineAssoc(Provider, "category", "data.attributes.category");
809defineAssoc(Provider, "remote", "meta.remote");
810defineAssoc(Provider, "editorConfig", "meta.editorConfig");
811Provider.endpoint = "providerTypes";
812
813class Asset extends RallyBase {
814 constructor({
815 data,
816 remote,
817 included
818 }) {
819 super();
820 this.data = data;
821 this.meta = {};
822 this.remote = remote;
823
824 if (included) {
825 this.meta.metadata = Asset.normalizeMetadata(included);
826 }
827 }
828
829 static normalizeMetadata(payload) {
830 let newMetadata = {};
831
832 for (let md of payload) {
833 if (md.type !== "metadata") continue;
834 newMetadata[md.attributes.usage] = md.attributes.metadata;
835 }
836
837 return newMetadata;
838 }
839
840 static lite(id, remote) {
841 return new this({
842 data: {
843 id
844 },
845 remote
846 });
847 }
848
849 chalkPrint(pad = false) {
850 let id = String("A-" + (this.remote && this.remote + "-" + this.id || "LOCAL"));
851 if (pad) id = id.padStart(15);
852 return chalk`{green ${id}}: {blue ${this.data.attributes ? this.name : "(lite asset)"}}`;
853 }
854
855 static async createNew(name, env) {
856 let req = await lib.makeAPIRequest({
857 env,
858 path: "/assets",
859 method: "POST",
860 payload: {
861 data: {
862 attributes: {
863 name
864 },
865 type: "assets"
866 }
867 }
868 });
869 return new this({
870 data: req.data,
871 remote: env
872 });
873 }
874
875 async delete() {
876 let req = await lib.makeAPIRequest({
877 env: this.remote,
878 path: "/assets/" + this.id,
879 method: "DELETE"
880 });
881 }
882
883 async addFile(label, fileuris) {
884 if (!Array.isArray(fileuris)) fileuris = [fileuris];
885 let instances = {};
886
887 for (let i = 0; i < fileuris.length; i++) {
888 instances[String(i + 1)] = {
889 uri: fileuris[i]
890 };
891 }
892
893 let req = await lib.makeAPIRequest({
894 env: this.remote,
895 path: "/files",
896 method: "POST",
897 payload: {
898 "data": {
899 "attributes": {
900 label,
901 instances
902 },
903 "relationships": {
904 "asset": {
905 "data": {
906 id: this.id,
907 "type": "assets"
908 }
909 }
910 },
911 "type": "files"
912 }
913 }
914 });
915 return req;
916 }
917
918 async startWorkflow(jobName, initData) {
919 let attributes;
920
921 if (initData) {
922 //Convert init data to string
923 initData = typeof initData === "string" ? initData : JSON.stringify(initData);
924 attributes = {
925 initData
926 };
927 }
928
929 let req = await lib.makeAPIRequest({
930 env: this.remote,
931 path: "/workflows",
932 method: "POST",
933 payload: {
934 "data": {
935 "type": "workflows",
936 attributes,
937 "relationships": {
938 "movie": {
939 "data": {
940 id: this.id,
941 "type": "movies"
942 }
943 },
944 "rule": {
945 "data": {
946 "attributes": {
947 "name": jobName
948 },
949 "type": "rules"
950 }
951 }
952 }
953 }
954 }
955 });
956 return req;
957 }
958
959 static async startAnonWorkflow(env, jobName, initData) {
960 let attributes;
961
962 if (initData) {
963 //Convert init data to string
964 initData = typeof initData === "string" ? initData : JSON.stringify(initData);
965 attributes = {
966 initData
967 };
968 }
969
970 let req = await lib.makeAPIRequest({
971 env,
972 path: "/workflows",
973 method: "POST",
974 payload: {
975 "data": {
976 "type": "workflows",
977 attributes,
978 "relationships": {
979 "rule": {
980 "data": {
981 "attributes": {
982 "name": jobName
983 },
984 "type": "rules"
985 }
986 }
987 }
988 }
989 }
990 });
991 return req;
992 }
993
994 async startEvaluate(presetid) {
995 // Fire and forget.
996 let data = await lib.makeAPIRequest({
997 env: this.remote,
998 path: "/jobs",
999 method: "POST",
1000 payload: {
1001 data: {
1002 type: "jobs",
1003 relationships: {
1004 movie: {
1005 data: {
1006 id: this.id,
1007 type: "movies"
1008 }
1009 },
1010 preset: {
1011 data: {
1012 id: presetid,
1013 type: "presets"
1014 }
1015 }
1016 }
1017 }
1018 }
1019 });
1020 return data;
1021 }
1022
1023}
1024
1025defineAssoc(Asset, "id", "data.id");
1026defineAssoc(Asset, "name", "data.attributes.name");
1027defineAssoc(Asset, "remote", "meta.remote");
1028defineAssoc(Asset, "md", "meta.metadata");
1029Asset.endpoint = "movies";
1030
1031const home = os.homedir();
1032const colon = /:/g;
1033const siloLike = /(silo\-\w+?)s?\/([^\/]+)\.([\w1234567890]+)$/g;
1034function pathTransform(path$$1) {
1035 if (path$$1.includes(":")) {
1036 //Ignore the first colon in window-like filesystems
1037 path$$1 = path$$1.slice(0, 3) + path$$1.slice(3).replace(colon, "--");
1038 }
1039
1040 if (configObject.invertedPath) {
1041 path$$1 = path$$1.replace(siloLike, "$2-$1.$3");
1042 }
1043
1044 if (path$$1.includes("\\342\\200\\220")) {
1045 path$$1 = path$$1.replace("\\342\\200\\220", "‐");
1046 }
1047
1048 return path$$1;
1049}
1050function readFileSync(path$$1, options) {
1051 return fs__default.readFileSync(pathTransform(path$$1), options);
1052} //Create writefilesync, with ability to create directory if it doesnt exist
1053
1054function writeFileSync(path$$1, data, options, dircreated = false) {
1055 path$$1 = pathTransform(path$$1);
1056
1057 try {
1058 return fs__default.writeFileSync(path$$1, data, options);
1059 } catch (e) {
1060 if (dircreated) throw e;
1061 let directory = path.dirname(path$$1);
1062
1063 try {
1064 fs__default.statSync(directory);
1065 throw e;
1066 } catch (nodir) {
1067 fs__default.mkdirSync(directory);
1068 return writeFileSync(path$$1, data, options, true);
1069 }
1070 }
1071}
1072
1073let exists = {};
1074
1075class Preset extends RallyBase {
1076 constructor({
1077 path: path$$1,
1078 remote,
1079 data,
1080 subProject
1081 } = {}) {
1082 // Get full path if possible
1083 if (path$$1) {
1084 path$$1 = path.resolve(path$$1);
1085
1086 if (path.dirname(path$$1).includes("silo-metadata")) {
1087 throw new AbortError("Constructing preset from metadata file");
1088 }
1089 }
1090
1091 super(); // Cache by path
1092
1093 if (path$$1) {
1094 if (exists[pathTransform(path$$1)]) return exists[pathTransform(path$$1)];
1095 exists[pathTransform(path$$1)] = this;
1096 }
1097
1098 this.meta = {};
1099 this.subproject = subProject;
1100 this.remote = remote;
1101
1102 if (lib.isLocalEnv(this.remote)) {
1103 if (path$$1) {
1104 this.path = path$$1;
1105 let pathspl = this.path.split(".");
1106 this.ext = pathspl[pathspl.length - 1];
1107
1108 try {
1109 this.code = this.getLocalCode();
1110 } catch (e) {
1111 if (e.code === "ENOENT" && configObject.ignoreMissing) {
1112 this.missing = true;
1113 return undefined;
1114 } else {
1115 log(chalk`{red Node Error} ${e.message}`);
1116 throw new AbortError("Could not load code of local file");
1117 }
1118 }
1119
1120 let name = this.parseFilenameForName() || this.parseCodeForName();
1121
1122 try {
1123 this.data = this.getLocalMetadata();
1124 this.isGeneric = true;
1125 name = this.name;
1126 } catch (e) {
1127 log(chalk`{yellow Warning}: ${path$$1} does not have a readable metadata file! Looking for ${this.localmetadatapath}`);
1128 this.data = Preset.newShell();
1129 this.isGeneric = false;
1130 }
1131
1132 this.name = name;
1133 } else {
1134 this.data = Preset.newShell();
1135 }
1136 } else {
1137 this.data = data; //this.name = data.attributes.name;
1138 //this.id = data.id;
1139
1140 this.isGeneric = false;
1141 }
1142
1143 this.data.attributes.rallyConfiguration = undefined;
1144 this.data.attributes.systemManaged = undefined;
1145 } //Given a metadata file, get its actualy file
1146
1147
1148 static async fromMetadata(path$$1, subproject) {
1149 let data;
1150
1151 try {
1152 data = JSON.parse(readFileSync(path$$1));
1153 } catch (e) {
1154 if (e.code === "ENOENT" && configObject.ignoreMissing) {
1155 return null;
1156 } else {
1157 throw e;
1158 }
1159 }
1160
1161 let providerType = data.relationships.providerType.data.name;
1162 let provider = await Provider.getByName("DEV", providerType);
1163
1164 if (!provider) {
1165 log(chalk`{red The provider type {green ${providerType}} does not exist}`);
1166 log(chalk`{red Skipping {green ${path$$1}}.}`);
1167 return null;
1168 }
1169
1170 let ext = await provider.getFileExtension();
1171 let name = data.attributes.name;
1172 let realpath = Preset.getLocalPath(name, ext, subproject);
1173 return new Preset({
1174 path: realpath,
1175 subProject: subproject
1176 });
1177 }
1178
1179 static newShell() {
1180 return {
1181 "attributes": {
1182 "providerSettings": {}
1183 },
1184 "relationships": {},
1185 "type": "presets"
1186 };
1187 }
1188
1189 cleanup() {
1190 super.cleanup();
1191 delete this.attributes["createdAt"];
1192 delete this.attributes["updatedAt"];
1193 }
1194
1195 async acclimatize(env) {
1196 if (!this.isGeneric) throw new AbortError("Cannot acclimatize non-generics or shells");
1197 let providers = await Provider.getAll(env);
1198 let ptype = this.relationships["providerType"];
1199 ptype = ptype.data;
1200 let provider = providers.findByName(ptype.name);
1201 ptype.id = provider.id;
1202 }
1203
1204 get test() {
1205 if (!this.code) return [];
1206 const regex = /[^-]autotest:\s?([\w\d_\-. \/]+)[\r\s\n]*?/gm;
1207 let match;
1208 let matches = [];
1209
1210 while (match = regex.exec(this.code)) {
1211 matches.push(match[1]);
1212 }
1213
1214 return matches;
1215 }
1216
1217 async runTest(env) {
1218 let remote = await Preset.getByName(env, this.name);
1219
1220 for (let test of this.test) {
1221 log("Tests...");
1222 let asset;
1223
1224 if (test.startsWith("id")) {
1225 let match = /id:\s*(\d+)/g.exec(test);
1226
1227 if (!match) {
1228 log(chalk`{red Could not parse autotest} ${test}.`);
1229 throw new AbortError("Could not properly parse the preset header");
1230 }
1231
1232 asset = await Asset.getById(env, match[1]);
1233 } else {
1234 asset = await Asset.getByName(env, test);
1235 }
1236
1237 if (!asset) {
1238 log(chalk`{yellow No movie found}, skipping test.`);
1239 continue;
1240 }
1241
1242 log(chalk`Starting job {green ${this.name}} on ${asset.chalkPrint(false)}... `);
1243 await asset.startEvaluate(remote.id);
1244 }
1245 }
1246
1247 async resolve() {
1248 if (this.isGeneric) return;
1249 let proType = await this.resolveField(Provider, "providerType");
1250 this.ext = await proType.getFileExtension();
1251 this.isGeneric = true;
1252 return {
1253 proType
1254 };
1255 }
1256
1257 async saveLocal() {
1258 await this.saveLocalMetadata();
1259 await this.saveLocalFile();
1260 }
1261
1262 async saveLocalMetadata() {
1263 if (!this.isGeneric) {
1264 await this.resolve();
1265 this.cleanup();
1266 }
1267
1268 writeFileSync(this.localmetadatapath, JSON.stringify(this.data, null, 4));
1269 }
1270
1271 async saveLocalFile() {
1272 writeFileSync(this.localpath, this.code);
1273 }
1274
1275 async uploadRemote(env) {
1276 await this.uploadCodeToEnv(env, true);
1277 }
1278
1279 async save(env) {
1280 this.saved = true;
1281
1282 if (!this.isGeneric) {
1283 await this.resolve();
1284 }
1285
1286 this.cleanup();
1287
1288 if (lib.isLocalEnv(env)) {
1289 log(chalk`Saving preset {green ${this.name}} to {blue ${lib.envName(env)}}.`);
1290 await this.saveLocal();
1291 } else {
1292 await this.uploadRemote(env);
1293 }
1294 }
1295
1296 async downloadCode() {
1297 if (!this.remote || this.code) return this.code;
1298 return this.code = await lib.makeAPIRequest({
1299 env: this.remote,
1300 path_full: this.data.links.providerData,
1301 json: false
1302 });
1303 }
1304
1305 get code() {
1306 if (this._code) return this._code;
1307 }
1308
1309 set code(v) {
1310 this._code = v;
1311 }
1312
1313 chalkPrint(pad = true) {
1314 let id = String("P-" + (this.remote && this.remote + "-" + this.id || "LOCAL"));
1315 let sub = "";
1316
1317 if (this.subproject) {
1318 sub = chalk`{yellow ${this.subproject}}`;
1319 }
1320
1321 if (pad) id = id.padStart(10);
1322
1323 if (this.name == undefined) {
1324 return chalk`{green ${id}}: ${sub}{red ${this.path}}`;
1325 } else if (this.meta.proType) {
1326 return chalk`{green ${id}}: ${sub}{red ${this.meta.proType.name}} {blue ${this.name}}`;
1327 } else {
1328 return chalk`{green ${id}}: ${sub}{blue ${this.name}}`;
1329 }
1330 }
1331
1332 parseFilenameForName() {
1333 if (this.path.endsWith(".jinja") || this.path.endsWith(".json")) {
1334 return path.basename(this.path).replace("_", " ").replace("-", " ").replace(".json", "").replace(".jinja", "");
1335 }
1336 }
1337
1338 parseCodeForName() {
1339 const name_regex = /name\s?:\s([\w\d. \/]+)[\r\s\n]*?/;
1340 const match = name_regex.exec(this.code);
1341 if (match) return match[1];
1342 }
1343
1344 findStringsInCode(strings) {
1345 if (!this.code) return [];
1346 return strings.filter(str => {
1347 let regex = new RegExp(str);
1348 return !!this.code.match(regex);
1349 });
1350 }
1351
1352 static getLocalPath(name, ext, subproject) {
1353 return path__default.join(configObject.repodir, subproject || "", "silo-presets", name + "." + ext);
1354 }
1355
1356 get localpath() {
1357 return Preset.getLocalPath(this.name, this.ext, this.subproject);
1358 }
1359
1360 get path() {
1361 if (this._path) return this._path;
1362 }
1363
1364 set path(val) {
1365 this._path = val;
1366 }
1367
1368 get name() {
1369 return this._nameOuter;
1370 }
1371
1372 set name(val) {
1373 if (!this._nameInner) this._nameInner = val;
1374 this._nameOuter = val;
1375 }
1376
1377 set providerType(value) {
1378 this.relationships["providerType"] = {
1379 data: { ...value,
1380 type: "providerTypes"
1381 }
1382 };
1383 }
1384
1385 get localmetadatapath() {
1386 if (this.path) {
1387 return this.path.replace("silo-presets", "silo-metadata").replace(new RegExp(this.ext + "$"), "json");
1388 }
1389
1390 return path__default.join(configObject.repodir, this.subproject || "", "silo-metadata", this.name + ".json");
1391 }
1392
1393 get immutable() {
1394 return this.name.includes("Constant");
1395 }
1396
1397 async uploadPresetData(env, id) {
1398 let res = await lib.makeAPIRequest({
1399 env,
1400 path: `/presets/${id}/providerData`,
1401 body: this.code,
1402 method: "PUT",
1403 fullResponse: true,
1404 timeout: 5000
1405 });
1406 write(chalk`code up {yellow ${res.statusCode}}, `);
1407 }
1408
1409 async grabMetadata(env) {
1410 let remote = await Preset.getByName(env, this.name);
1411 this.isGeneric = false;
1412
1413 if (!remote) {
1414 throw new AbortError(`No file found on remote ${env} with name ${this.name}`);
1415 }
1416
1417 this.data = remote.data;
1418 this.remote = env;
1419 }
1420
1421 async uploadCodeToEnv(env, includeMetadata, shouldTest = true) {
1422 if (!this.name) {
1423 log(chalk`Failed uploading {red ${this.path}}. No name found.`);
1424 return;
1425 }
1426
1427 write(chalk`Uploading preset {green ${this.name}} to {green ${env}}: `);
1428
1429 if (this.immutable) {
1430 log(chalk`{magenta IMMUTABLE}. Nothing to do.`);
1431 return;
1432 } //First query the api to see if this already exists.
1433
1434
1435 let remote = await Preset.getByName(env, this.name);
1436
1437 if (remote) {
1438 //If it exists we can replace it
1439 write("replace, ");
1440
1441 if (includeMetadata) {
1442 let res = await lib.makeAPIRequest({
1443 env,
1444 path: `/presets/${remote.id}`,
1445 method: "PATCH",
1446 payload: {
1447 data: {
1448 attributes: this.data.attributes,
1449 type: "presets"
1450 }
1451 },
1452 fullResponse: true
1453 });
1454 write(chalk`metadata {yellow ${res.statusCode}}, `);
1455 }
1456
1457 await this.uploadPresetData(env, remote.id);
1458 } else {
1459 write("create, ");
1460 let metadata = {
1461 data: this.data
1462 };
1463
1464 if (!this.relationships["providerType"]) {
1465 throw new AbortError("Cannot acclimatize shelled presets. (try creating it on the env first)");
1466 }
1467
1468 await this.acclimatize(env);
1469 write("Posting to create preset... ");
1470 let res = await lib.makeAPIRequest({
1471 env,
1472 path: `/presets`,
1473 method: "POST",
1474 payload: metadata,
1475 timeout: 5000
1476 });
1477 let id = res.data.id;
1478 write(chalk`Created id {green ${id}}... Uploading Code... `);
1479 await this.uploadPresetData(env, id);
1480 }
1481
1482 if (this.test[0] && shouldTest) {
1483 await this.runTest(env);
1484 } else {
1485 log("No tests. Done.");
1486 }
1487 }
1488
1489 getLocalMetadata() {
1490 return JSON.parse(readFileSync(this.localmetadatapath, "utf-8"));
1491 }
1492
1493 getLocalCode() {
1494 return readFileSync(this.path, "utf-8");
1495 }
1496
1497}
1498
1499defineAssoc(Preset, "_nameInner", "data.attributes.providerSettings.PresetName");
1500defineAssoc(Preset, "_nameOuter", "data.attributes.name");
1501defineAssoc(Preset, "id", "data.id");
1502defineAssoc(Preset, "attributes", "data.attributes");
1503defineAssoc(Preset, "relationships", "data.relationships");
1504defineAssoc(Preset, "remote", "meta.remote");
1505defineAssoc(Preset, "_code", "meta.code");
1506defineAssoc(Preset, "_path", "meta.path");
1507defineAssoc(Preset, "isGeneric", "meta.isGeneric");
1508defineAssoc(Preset, "ext", "meta.ext");
1509defineAssoc(Preset, "subproject", "meta.project");
1510defineAssoc(Preset, "metastring", "meta.metastring");
1511Preset.endpoint = "presets";
1512
1513class Notification extends RallyBase {
1514 constructor({
1515 data,
1516 remote
1517 }) {
1518 super();
1519 this.data = data;
1520 this.meta = {};
1521 this.remote = remote;
1522 }
1523
1524 static async getAllPreCollect(notifications) {
1525 return notifications.sort((a, b) => {
1526 return a.attributes.type.localeCompare(b.attributes.type) || a.attributes.name.localeCompare(b.attributes.name);
1527 });
1528 }
1529
1530 chalkPrint(pad = false) {
1531 let id = String("N-" + this.id);
1532 if (pad) id = id.padStart(4);
1533 return chalk`{green ${id}}: {blue ${this.type}} - {green ${this.name}}`;
1534 }
1535
1536}
1537
1538defineAssoc(Notification, "id", "data.id");
1539defineAssoc(Notification, "name", "data.attributes.name");
1540defineAssoc(Notification, "address", "data.attributes.address");
1541defineAssoc(Notification, "type", "data.attributes.type");
1542defineAssoc(Notification, "remote", "meta.remote");
1543Notification.endpoint = "notificationPresets";
1544
1545class Rule extends RallyBase {
1546 constructor({
1547 path: path$$1,
1548 data,
1549 remote,
1550 subProject
1551 } = {}) {
1552 super();
1553
1554 if (path$$1) {
1555 path$$1 = path.resolve(path$$1);
1556
1557 try {
1558 let f = readFileSync(path$$1, "utf-8");
1559 data = JSON.parse(readFileSync(path$$1, "utf-8"));
1560 } catch (e) {
1561 if (e.code === "ENOENT") {
1562 if (configObject.ignoreMissing) {
1563 this.missing = true;
1564 return undefined;
1565 } else {
1566 throw new AbortError("Could not load code of local file");
1567 }
1568 } else {
1569 throw new AbortError(`Unreadable JSON in ${path$$1}. ${e}`);
1570 }
1571 }
1572 }
1573
1574 this.meta = {};
1575 this.subproject = subProject;
1576
1577 if (!data) {
1578 data = Rule.newShell();
1579 }
1580
1581 this.data = data;
1582 this.remote = remote;
1583 this.isGeneric = !this.remote;
1584 }
1585
1586 static newShell() {
1587 return {
1588 "attributes": {
1589 "description": "-",
1590 "priority": "PriorityNorm",
1591 "starred": false
1592 },
1593 "relationships": {},
1594 "type": "workflowRules"
1595 };
1596 }
1597
1598 async acclimatize(env) {
1599 this.remote = env;
1600 let preset = await this.resolveField(Preset, "preset", false, "specific");
1601 let pNext = await this.resolveField(Rule, "passNext", false, "specific");
1602 let eNext = await this.resolveField(Rule, "errorNext", false, "specific");
1603 let proType = await this.resolveField(Provider, "providerType", false, "specific");
1604 let dynamicNexts = await this.resolveField(Rule, "dynamicNexts", true, "specific");
1605 let enterNotif = await this.resolveField(Notification, "enterNotifications", true, "specific");
1606 let errorNotif = await this.resolveField(Notification, "errorNotifications", true, "specific");
1607 let passNotif = await this.resolveField(Notification, "passNotifications", true, "specific");
1608 }
1609
1610 async saveA(env) {
1611 if (lib.isLocalEnv(env)) return;
1612 return await this.createIfNotExist(env);
1613 }
1614
1615 async saveB(env) {
1616 if (!this.isGeneric) {
1617 await this.resolve();
1618 }
1619
1620 this.cleanup();
1621
1622 if (lib.isLocalEnv(env)) {
1623 log(chalk`Saving rule {green ${this.name}} to {blue ${lib.envName(env)}}.`);
1624 writeFileSync(this.localpath, JSON.stringify(this.data, null, 4));
1625 } else {
1626 await this.acclimatize(env);
1627 await this.uploadRemote(env);
1628 }
1629 }
1630
1631 get immutable() {
1632 return false;
1633 }
1634
1635 async createIfNotExist(env) {
1636 write(chalk`First pass rule {green ${this.name}} to {green ${env}}: `);
1637
1638 if (this.immutable) {
1639 log(chalk`{magenta IMMUTABLE}. Nothing to do.`);
1640 return;
1641 } //First query the api to see if this already exists.
1642
1643
1644 let remote = await Rule.getByName(env, this.name);
1645 this.idMap = this.idMap || {};
1646
1647 if (remote) {
1648 this.idMap[env] = remote.id;
1649 log(chalk`exists ${remote.chalkPrint(false)}`);
1650 return;
1651 } //If it exists we can replace it
1652
1653
1654 write("create, ");
1655 let res = await lib.makeAPIRequest({
1656 env,
1657 path: `/workflowRules`,
1658 method: "POST",
1659 payload: {
1660 data: {
1661 attributes: {
1662 name: this.name
1663 },
1664 type: "workflowRules"
1665 }
1666 }
1667 });
1668 this.idMap = this.idMap || {};
1669 this.idMap[env] = res.data.id;
1670 write("id ");
1671 log(this.idMap[env]);
1672 }
1673
1674 async patchStrip() {
1675 delete this.data.attributes.createdAt;
1676 delete this.data.attributes.starred;
1677 delete this.data.attributes.updatedAt; // TEMP FIX FOR BUG IN SDVI
1678
1679 if (this.relationships.passMetadata && this.relationships.passMetadata[0]) {
1680 log("HAS PASS");
1681 log(this.name);
1682 log("HAS PASS");
1683 }
1684
1685 delete this.relationships.passMetadata;
1686
1687 if (this.relationships.errorMetadata && this.relationships.errorMetadata[0]) {
1688 log("HAS PASS");
1689 log(this.name);
1690 log("HAS PASS");
1691 }
1692
1693 delete this.relationships.errorMetadata; // This is commented out because it was fixed.
1694 //for(let key in this.relationships){
1695 //let relationship = this.relationships[key];
1696 //if(!relationship.data || relationship.data instanceof Array && !relationship.data[0]){
1697 //delete this.relationships[key];
1698 //}
1699 //}
1700 }
1701
1702 async uploadRemote(env) {
1703 write(chalk`Uploading rule {green ${this.name}} to {green ${env}}: `);
1704
1705 if (this.immutable) {
1706 log(chalk`{magenta IMMUTABLE}. Nothing to do.`);
1707 return;
1708 }
1709
1710 if (this.idMap[env]) {
1711 this.remote = env;
1712 await this.patchStrip();
1713 this.data.id = this.idMap[env]; //If it exists we can replace it
1714
1715 write("replace, ");
1716 let res = await lib.makeAPIRequest({
1717 env,
1718 path: `/workflowRules/${this.idMap[env]}`,
1719 method: "PATCH",
1720 payload: {
1721 data: this.data
1722 },
1723 fullResponse: true
1724 });
1725 log(chalk`response {yellow ${res.statusCode}}`);
1726
1727 if (res.statusCode !== 200) {
1728 log(res.body);
1729 log(JSON.stringify(this.data, null, 4));
1730 }
1731 } else {
1732 throw Error("Bad idmap!");
1733 }
1734 }
1735
1736 get localpath() {
1737 return path.join(configObject.repodir, this.subproject || "", "silo-rules", this.name + ".json");
1738 }
1739
1740 async resolve() {
1741 let preset = await this.resolveField(Preset, "preset", false); //log(preset);
1742
1743 let pNext = await this.resolveField(Rule, "passNext", false);
1744 let eNext = await this.resolveField(Rule, "errorNext", false);
1745 let proType = await this.resolveField(Provider, "providerType", false); //log("Dynamic nexts")
1746
1747 let dynamicNexts = await this.resolveField(Rule, "dynamicNexts", true); //log(dynamicNexts);
1748
1749 let enterNotif = await this.resolveField(Notification, "enterNotifications", true);
1750 let errorNotif = await this.resolveField(Notification, "errorNotifications", true);
1751 let passNotif = await this.resolveField(Notification, "passNotifications", true); //TODO Unsupported
1752
1753 delete this.relationships["enterMetadata"];
1754 delete this.relationships["errorMetadata"];
1755 this.isGeneric = true;
1756 return {
1757 preset,
1758 proType,
1759 pNext,
1760 eNext,
1761 dynamicNexts,
1762 errorNotif,
1763 enterNotif,
1764 passNotif
1765 };
1766 }
1767
1768 chalkPrint(pad = true) {
1769 let id = String("R-" + (this.remote && this.remote + "-" + this.id || "LOCAL"));
1770 let sub = "";
1771
1772 if (this.subproject) {
1773 sub = chalk`{yellow ${this.subproject}}`;
1774 }
1775
1776 if (pad) id = id.padStart(10);
1777
1778 try {
1779 return chalk`{green ${id}}: ${sub}{blue ${this.name}}`;
1780 } catch (e) {
1781 return this.data;
1782 }
1783 }
1784
1785}
1786
1787defineAssoc(Rule, "name", "data.attributes.name");
1788defineAssoc(Rule, "description", "data.attributes.description");
1789defineAssoc(Rule, "id", "data.id");
1790defineAssoc(Rule, "relationships", "data.relationships");
1791defineAssoc(Rule, "isGeneric", "meta.isGeneric");
1792defineAssoc(Rule, "remote", "meta.remote");
1793defineAssoc(Rule, "subproject", "meta.project");
1794defineAssoc(Rule, "idMap", "meta.idMap");
1795Rule.endpoint = "workflowRules";
1796
1797//Move project into silo metadata
1798//move autotest into silo metadata
1799//
1800
1801class SupplyChain {
1802 constructor(startingRule, stopRule) {
1803 if (startingRule) {
1804 this.startingRule = startingRule;
1805 this.stopRule = stopRule;
1806 this.remote = startingRule.remote;
1807 }
1808 }
1809
1810 async downloadPresetCode(objs = this.allPresets) {
1811 log("Downloading code... ");
1812 await lib.keepalive(objs.arr.map(x => () => x.downloadCode()));
1813 }
1814
1815 async calculate() {
1816 log("Getting rules... ");
1817 this.allRules = await Rule.getAll(this.remote);
1818 log(this.allRules.length);
1819 log("Getting presets... ");
1820 this.allPresets = await Preset.getAll(this.remote);
1821 log(this.allPresets.length);
1822 log("Getting providers... ");
1823 this.allProviders = await Provider.getAll(this.remote);
1824 log(this.allProviders.length);
1825 log("Getting notifications... ");
1826 this.allNotifications = await Notification.getAll(this.remote);
1827 log(this.allNotifications.length);
1828
1829 if (!this.startingRule) {
1830 this.rules = this.allRules;
1831 this.presets = this.allPresets;
1832 this.notifications = new Collection([]);
1833 await this.downloadPresetCode();
1834 return;
1835 } else {
1836 await this.downloadPresetCode();
1837 }
1838
1839 log("Done!"); //Now we have everything we need to find a whole supply chain
1840
1841 write("Calculating Supply chain... ");
1842 log(this.startingRule.chalkPrint());
1843 let allRuleNames = this.allRules.arr.map(x => x.name).filter(x => x.length >= 4);
1844 let allPresetNames = this.allPresets.arr.map(x => x.name).filter(x => x.length >= 4);
1845 let allNotifNames = this.allNotifications.arr.map(x => x.name).filter(x => x.length >= 4);
1846 let requiredNotifications = new Set();
1847 let ruleQueue = [this.startingRule];
1848 let presetQueue = [];
1849
1850 for (let currentRule of ruleQueue) {
1851 if (currentRule === this.stopRule) continue;
1852 let {
1853 eNext,
1854 pNext,
1855 preset,
1856 passNotif,
1857 errorNotif,
1858 enterNotif
1859 } = await currentRule.resolve();
1860 passNotif.forEach(n => requiredNotifications.add(n));
1861 enterNotif.forEach(n => requiredNotifications.add(n));
1862 errorNotif.forEach(n => requiredNotifications.add(n));
1863 if (eNext && !ruleQueue.includes(eNext)) ruleQueue.push(eNext);
1864 if (pNext && !ruleQueue.includes(eNext)) ruleQueue.push(pNext);
1865 let neededPresets = preset.findStringsInCode(allPresetNames);
1866 neededPresets = neededPresets.map(x => this.allPresets.findByName(x));
1867 let neededRules = preset.findStringsInCode(allRuleNames);
1868 neededRules = neededRules.map(x => this.allRules.findByName(x));
1869 preset.findStringsInCode(allNotifNames).map(str => this.allNotifications.findByName(str)).forEach(notif => requiredNotifications.add(notif));
1870 neededPresets.push(preset);
1871
1872 for (let p of neededPresets) if (!presetQueue.includes(p)) presetQueue.push(p);
1873
1874 for (let p of neededRules) if (!ruleQueue.includes(p)) ruleQueue.push(p);
1875
1876 if (configObject.verbose) {
1877 write(currentRule.chalkPrint(false));
1878 log(":");
1879 write(" ");
1880 write(preset.chalkPrint(false));
1881 log(":");
1882 write(" Pass Next: ");
1883 if (pNext) write(pNext.chalkPrint(false));else write("None");
1884 log("");
1885 write(" Err Next: ");
1886 if (eNext) write(eNext.chalkPrint(false));else write("None");
1887 log("");
1888 log(" Rules:");
1889
1890 for (let p of neededRules) log(" " + p.chalkPrint(true));
1891
1892 log(" Presets:");
1893
1894 for (let p of neededPresets) log(" " + p.chalkPrint(true));
1895
1896 log("\n");
1897 }
1898 }
1899
1900 log("Done!");
1901 this.rules = new Collection(ruleQueue);
1902 this.presets = new Collection(presetQueue);
1903 requiredNotifications.delete(undefined);
1904 this.notifications = new Collection([...requiredNotifications]);
1905 }
1906
1907 async log() {
1908 if (this.notifications.arr.length > 0) {
1909 log("Required notifications: ");
1910 this.notifications.log();
1911 }
1912
1913 if (this.rules.arr.length > 0) {
1914 write("Required rules: ");
1915 log(this.rules.arr.length);
1916 this.rules.log();
1917 }
1918
1919 if (this.presets.arr.length > 0) {
1920 write("Required presets: ");
1921 log(this.presets.arr.length);
1922 this.presets.log();
1923 }
1924
1925 if (configObject.rawOutput) {
1926 return {
1927 presets: this.presets.arr,
1928 rules: this.rules.arr,
1929 notifications: this.notifications.arr
1930 };
1931 }
1932 }
1933
1934 async syncTo(env) {
1935 for (let preset of this.presets) {
1936 try {
1937 await preset.save(env);
1938 } catch (e) {
1939 log(e);
1940 }
1941 }
1942
1943 if (this.rules.arr[0]) {
1944 log("Starting create phase for rules");
1945
1946 for (let rule of this.rules) {
1947 try {
1948 await rule.saveA(env);
1949 } catch (e) {
1950 log(e);
1951 }
1952 }
1953
1954 log("OK");
1955 log("Starting link phase for rules");
1956 Rule.removeCache(env);
1957
1958 for (let rule of this.rules) {
1959 try {
1960 await rule.saveB(env);
1961 } catch (e) {
1962 log(e);
1963 }
1964 }
1965 }
1966 }
1967
1968}
1969
1970class User extends RallyBase {
1971 constructor({
1972 data,
1973 remote
1974 }) {
1975 super();
1976 this.data = data;
1977 this.meta = {};
1978 this.remote = remote;
1979 }
1980
1981 chalkPrint(pad = false) {
1982 let id = String("U-" + this.id);
1983 if (pad) id = id.padStart(7);
1984 return chalk`{green ${id}}: {blue ${this.name}}`;
1985 }
1986
1987}
1988
1989defineAssoc(User, "id", "data.id");
1990defineAssoc(User, "name", "data.attributes.name");
1991defineAssoc(User, "email", "data.attributes.email");
1992defineAssoc(User, "remote", "meta.remote");
1993User.endpoint = "users";
1994
1995class Tag extends RallyBase {
1996 constructor({
1997 data,
1998 remote
1999 } = {}) {
2000 super();
2001 this.meta = {};
2002 this.remote = remote;
2003 this.data = data; //this.data.attributes.rallyConfiguration = undefined;
2004 //this.data.attributes.systemManaged = undefined;
2005 }
2006
2007 chalkPrint(pad = true) {
2008 let id = String("T-" + this.remote + "-" + this.id);
2009 if (pad) id = id.padStart(10);
2010 let prefix = this.curated ? "blue +" : "red -";
2011 return chalk`{green ${id}}: {${prefix}${this.name}}`;
2012 }
2013
2014 static async create(env, name, {
2015 notCurated
2016 } = {}) {
2017 return new Tag({
2018 data: await lib.makeAPIRequest({
2019 env,
2020 path: `/${this.endpoint}`,
2021 method: "POST",
2022 payload: {
2023 data: {
2024 attributes: {
2025 name,
2026 curated: notCurated ? false : true
2027 },
2028 type: "tagNames"
2029 }
2030 }
2031 }),
2032 remote: env
2033 });
2034 }
2035
2036}
2037
2038defineAssoc(Tag, "id", "data.id");
2039defineAssoc(Tag, "attributes", "data.attributes");
2040defineAssoc(Tag, "relationships", "data.relationships");
2041defineAssoc(Tag, "name", "data.attributes.name");
2042defineAssoc(Tag, "curated", "data.attributes.curated");
2043defineAssoc(Tag, "remote", "meta.remote");
2044Tag.endpoint = "tagNames";
2045
2046require("source-map-support").install();
2047const rallyFunctions = {
2048 async bestPagintation() {
2049 global.silentAPI = true;
2050
2051 for (let i = 10; i <= 30; i += 5) {
2052 console.time("test with " + i);
2053 let dl = await lib.indexPathFast("DEV", `/workflowRules?page=1p${i}`);
2054 console.timeEnd("test with " + i);
2055 }
2056 },
2057
2058 async uploadPresets(env, presets, createFunc = () => false) {
2059 for (let preset of presets) {
2060 await preset.uploadCodeToEnv(env, createFunc);
2061 }
2062 },
2063
2064 //Dummy test access
2065 async testAccess(env) {
2066 if (lib.isLocalEnv(env)) {
2067 //TODO
2068 return true;
2069 }
2070
2071 let result = await lib.makeAPIRequest({
2072 env,
2073 path: "/providers?page=1p1",
2074 fullResponse: true,
2075 timeout: 1000
2076 });
2077 return result.statusCode;
2078 }
2079
2080};
2081
2082var allIndexBundle = /*#__PURE__*/Object.freeze({
2083 rallyFunctions: rallyFunctions,
2084 SupplyChain: SupplyChain,
2085 Preset: Preset,
2086 Rule: Rule,
2087 Provider: Provider,
2088 Notification: Notification,
2089 Asset: Asset,
2090 User: User,
2091 Tag: Tag,
2092 get configFile () { return configFile; },
2093 loadConfig: loadConfig,
2094 setConfig: setConfig,
2095 get configObject () { return configObject; },
2096 lib: lib,
2097 AbortError: AbortError,
2098 APIError: APIError,
2099 UnconfiguredEnvError: UnconfiguredEnvError,
2100 ProtectedEnvError: ProtectedEnvError,
2101 Collection: Collection,
2102 RallyBase: RallyBase
2103});
2104
2105var version = "1.13.0";
2106
2107var baseCode = {
2108 SdviContentMover: `{
2109 "tasks": [
2110 {
2111 "operation": "move",
2112 "source": {
2113 "labels": [ "MyLabel" ],
2114 "tags": [ "segmented" ]
2115 "storageSet": [ "*", "-OtherStorageBucket" ],
2116
2117 },
2118 "destination": {
2119 "storage": "Archive",
2120 "newLabel": "myNewLabel",
2121 "overwrite": "always"
2122 }
2123 }
2124 ]
2125}`,
2126 SdviEvaluate: `'''
2127name: {name}
2128'''
2129
2130# code here`
2131};
2132
2133const inquirer = importLazy("inquirer");
2134const readdir = importLazy("recursive-readdir");
2135let hasAutoCompletePrompt = false;
2136function addAutoCompletePrompt() {
2137 if (hasAutoCompletePrompt) return;
2138 hasAutoCompletePrompt = true;
2139 inquirer.registerPrompt("autocomplete", require("inquirer-autocomplete-prompt"));
2140}
2141async function $api(propArray) {
2142 let q;
2143 q = await inquirer.prompt([{
2144 type: "input",
2145 name: "company",
2146 message: `What is your company?`,
2147 default: `discovery`
2148 }]);
2149 let company = q.company;
2150 const defaults = {
2151 DEV: `https://${company}-dev.sdvi.com/api/v2`,
2152 UAT: `https://${company}-uat.sdvi.com/api/v2`,
2153 QA: `https://${company}-qa.sdvi.com/api/v2`,
2154 PROD: `https://${company}.sdvi.com/api/v2`
2155 };
2156
2157 if (propArray && propArray[1]) {
2158 q = {
2159 envs: [propArray[1]]
2160 };
2161 } else {
2162 //Create a checkbox prompt to choose enviornments
2163 q = await inquirer.prompt([{
2164 type: "checkbox",
2165 name: "envs",
2166 message: `What enviornments would you like to configure?`,
2167 choices: Object.keys(defaults).map(name => ({
2168 name,
2169 checked: true
2170 }))
2171 }]);
2172 } //Each env should ask 2 for two things: The url and the key.
2173
2174
2175 let questions = q.envs.map(env => {
2176 let defaultKey = process.env[`rally_api_key_${env}`];
2177
2178 if (configObject && configObject.api && configObject.api[env]) {
2179 defaultKey = configObject.api[env].key;
2180 }
2181
2182 return [{
2183 type: "input",
2184 name: `api.${env}.url`,
2185 message: `What is the api endpoint for ${env}?`,
2186 default: defaults[env]
2187 }, {
2188 type: "input",
2189 name: `api.${env}.key`,
2190 message: `What is your api key for ${env}?`,
2191 default: defaultKey
2192 }];
2193 }); //flatten and ask
2194
2195 questions = [].concat(...questions);
2196 q = await inquirer.prompt(questions);
2197
2198 if (propArray) {
2199 q.api = { ...configObject.api,
2200 ...q.api
2201 };
2202 }
2203
2204 return q;
2205}
2206async function $chalk(propArray) {
2207 return {
2208 chalk: await askQuestion("Would you like chalk enabled (Adds coloring)?")
2209 };
2210}
2211async function $restrictUAT(propArray) {
2212 return {
2213 restrictUAT: await askQuestion("Would you like to protect UAT?")
2214 };
2215}
2216async function $repodir(propArray) {
2217 return await inquirer.prompt([{
2218 type: "input",
2219 name: `repodir`,
2220 message: `Where is your rally repository?`,
2221 default: process.env["rally_repo_path"]
2222 }]);
2223}
2224async function $appName(propArray) {
2225 let defaultAppName = "cmdline-" + (process.env.USERNAME || process.env.LOGNAME);
2226 let project = await askInput("Application name?", defaultAppName);
2227
2228 if (project === "none" || project === "-" || project === "" || !project) {
2229 project = null;
2230 }
2231
2232 return {
2233 appName: project
2234 };
2235}
2236async function $project(propArray) {
2237 let project = await askInput("Subproject directory?");
2238
2239 if (project === "none" || project === "-" || project === "" || !project) {
2240 project = null;
2241 }
2242
2243 return {
2244 project
2245 };
2246}
2247async function $defaultEnv(propArray) {
2248 return await inquirer.prompt([{
2249 type: "input",
2250 name: `defaultEnv`,
2251 message: `Default enviornment?`,
2252 default: "DEV"
2253 }]);
2254} //Internal usage/testing
2255
2256async function selectProvider(providers, autoDefault = false) {
2257 addAutoCompletePrompt();
2258 let defaultProvider = providers.findByName("SdviEvaluate");
2259
2260 if (autoDefault) {
2261 return defaultProvider;
2262 } else {
2263 let choices = providers.arr.map(x => ({
2264 name: x.chalkPrint(true),
2265 value: x
2266 }));
2267 let q = await inquirer.prompt([{
2268 type: "autocomplete",
2269 name: "provider",
2270 default: defaultProvider,
2271 source: async (sofar, input) => {
2272 return choices.filter(x => input ? x.value.name.toLowerCase().includes(input.toLowerCase()) : true);
2273 }
2274 }]);
2275 return q.provider;
2276 }
2277}
2278async function selectLocal(path$$1, typeName, Class) {
2279 addAutoCompletePrompt();
2280 let basePath = configObject.repodir;
2281 let f = await readdir(basePath);
2282 let objs = f.filter(name => name.includes(path$$1)).map(name => new Class({
2283 path: name
2284 }));
2285 let objsMap = objs.map(x => ({
2286 name: x.chalkPrint(true),
2287 value: x
2288 }));
2289 let none = {
2290 name: chalk` {red None}: {red None}`,
2291 value: null
2292 };
2293 objsMap.unshift(none);
2294 let q = await inquirer.prompt([{
2295 type: "autocomplete",
2296 name: "obj",
2297 message: `What ${typeName} do you want?`,
2298 source: async (sofar, input) => {
2299 return objsMap.filter(x => input ? x.name.toLowerCase().includes(input.toLowerCase()) : true);
2300 }
2301 }]);
2302 return q.obj;
2303}
2304async function selectPreset(purpose = "preset") {
2305 return selectLocal("silo-presets", purpose, Preset);
2306}
2307async function selectRule(purpose = "rule") {
2308 return selectLocal("silo-rules", purpose, Rule);
2309}
2310async function askInput(question, def) {
2311 return (await inquirer.prompt([{
2312 type: "input",
2313 name: "ok",
2314 message: question,
2315 default: def
2316 }])).ok;
2317}
2318async function askQuestion(question) {
2319 return (await inquirer.prompt([{
2320 type: "confirm",
2321 name: "ok",
2322 message: question
2323 }])).ok;
2324}
2325
2326var configHelpers = /*#__PURE__*/Object.freeze({
2327 inquirer: inquirer,
2328 addAutoCompletePrompt: addAutoCompletePrompt,
2329 $api: $api,
2330 $chalk: $chalk,
2331 $restrictUAT: $restrictUAT,
2332 $repodir: $repodir,
2333 $appName: $appName,
2334 $project: $project,
2335 $defaultEnv: $defaultEnv,
2336 selectProvider: selectProvider,
2337 selectLocal: selectLocal,
2338 selectPreset: selectPreset,
2339 selectRule: selectRule,
2340 askInput: askInput,
2341 askQuestion: askQuestion
2342});
2343
2344var _dec, _dec2, _dec3, _dec4, _dec5, _dec6, _dec7, _dec8, _dec9, _dec10, _dec11, _dec12, _dec13, _dec14, _dec15, _dec16, _dec17, _dec18, _dec19, _dec20, _dec21, _dec22, _dec23, _dec24, _dec25, _dec26, _dec27, _dec28, _dec29, _dec30, _dec31, _dec32, _dec33, _dec34, _dec35, _dec36, _dec37, _dec38, _dec39, _dec40, _dec41, _dec42, _dec43, _dec44, _obj;
2345
2346require("source-map-support").install();
2347let argv = argparse(process.argv.slice(2), {
2348 string: ["file", "env"],
2349 //boolean: ["no-protect"],
2350 boolean: ["anon"],
2351 default: {
2352 protect: true
2353 },
2354 alias: {
2355 f: "file",
2356 e: "env"
2357 }
2358}); //help menu helper
2359
2360function printHelp(help, short) {
2361 let helpText$$1 = chalk`
2362{white ${help.name}}: ${help.text}
2363 Usage: ${help.usage || "<unknown>"}
2364`; //Trim newlines
2365
2366 helpText$$1 = helpText$$1.substring(1, helpText$$1.length - 1);
2367
2368 if (!short) {
2369 for (let param$$1 of help.params || []) {
2370 helpText$$1 += chalk`\n {blue ${param$$1.param}}: ${param$$1.desc}`;
2371 }
2372
2373 for (let arg$$1 of help.args || []) {
2374 helpText$$1 += chalk`\n {blue ${arg$$1.short}}, {blue ${arg$$1.long}}: ${arg$$1.desc}`;
2375 }
2376 }
2377
2378 return helpText$$1;
2379}
2380
2381async function getFilesFromArgs(args) {
2382 let lastArg = args._.shift();
2383
2384 if (args.file) {
2385 let files = args.file;
2386 if (typeof files === "string") files = [files];
2387 return files;
2388 }
2389
2390 if (lastArg == "-") {
2391 log("Reading from stdin");
2392
2393 let getStdin = require("get-stdin");
2394
2395 let stdin = await getStdin();
2396 let files = stdin.split("\n");
2397 if (files[files.length - 1] === "") files.pop();
2398 return files;
2399 } else {
2400 args._.push(lastArg);
2401 }
2402}
2403
2404let presetsub = {
2405 async before(args) {
2406 this.env = args.env;
2407 if (!this.env) throw new AbortError("No env supplied");
2408 this.files = await getFilesFromArgs(args);
2409 },
2410
2411 async $grab(args) {
2412 if (!this.files) {
2413 throw new AbortError("No files provided to grab (use --file argument)");
2414 }
2415
2416 log(chalk`Grabbing {green ${this.files.length}} preset(s) metadata from {green ${this.env}}.`);
2417 let presets = this.files.map(path$$1 => new Preset({
2418 path: path$$1,
2419 remote: false
2420 }));
2421
2422 for (let preset of presets) {
2423 //TODO small refactor
2424 await preset.grabMetadata(this.env);
2425 await preset.saveLocalMetadata();
2426
2427 if (args.full) {
2428 let remo = await Preset.getByName(this.env, preset.name);
2429 await remo.resolve();
2430 await remo.downloadCode();
2431 await remo.saveLocalFile();
2432 }
2433 }
2434 },
2435
2436 async $create(args) {
2437 let provider, name$$1, ext;
2438
2439 if (args.provider) {
2440 provider = {
2441 name: args.provider
2442 };
2443 ext = args.ext;
2444 } else {
2445 provider = await selectProvider((await Provider.getAll(this.env)));
2446 ext = (await provider.getEditorConfig()).fileExt;
2447 }
2448
2449 if (args.name) {
2450 name$$1 = args.name;
2451 } else {
2452 name$$1 = await askInput("Preset Name", "What is the preset name?");
2453 }
2454
2455 let preset = new Preset({
2456 subProject: configObject.project
2457 });
2458 preset.providerType = {
2459 name: provider.name
2460 };
2461 preset.isGeneric = true;
2462 preset.name = name$$1;
2463 preset.ext = ext;
2464
2465 if (baseCode[provider.name]) {
2466 preset._code = baseCode[provider.name].replace("{name}", name$$1);
2467 } else {
2468 preset._code = " ";
2469 }
2470
2471 preset.saveLocalMetadata();
2472 preset.saveLocalFile();
2473 },
2474
2475 async $list(args) {
2476 log("Loading...");
2477 let presets = await Preset.getAll(this.env);
2478
2479 if (args.resolve) {
2480 Provider.getAll(this.env);
2481
2482 for (let preset of presets) {
2483 let resolve = await preset.resolve(this.env);
2484
2485 if (args.attach) {
2486 let {
2487 proType
2488 } = resolve;
2489 proType.editorConfig.helpText = "";
2490 preset.meta = { ...preset.meta,
2491 proType
2492 };
2493 }
2494 }
2495 }
2496
2497 if (configObject.rawOutput) return presets;
2498 log(chalk`{yellow ${presets.length}} presets on {green ${this.env}}.`);
2499 presets.arr.sort((a, b) => {
2500 return Number(a.attributes.updatedAt) - Number(b.attributes.updatedAt);
2501 });
2502
2503 for (let preset of presets) {
2504 log(preset.chalkPrint());
2505 }
2506 },
2507
2508 async $upload(args) {
2509 if (!this.files) {
2510 throw new AbortError("No files provided to upload (use --file argument)");
2511 }
2512
2513 log(chalk`Uploading {green ${this.files.length}} preset(s) to {green ${this.env}}.`);
2514 let presets = this.files.map(path$$1 => new Preset({
2515 path: path$$1,
2516 remote: false
2517 }));
2518 await rallyFunctions.uploadPresets(this.env, presets);
2519 },
2520
2521 async $diff(args) {
2522 let file = this.files[0];
2523
2524 if (!this.files) {
2525 throw new AbortError("No files provided to diff (use --file argument)");
2526 }
2527
2528 let preset = new Preset({
2529 path: file,
2530 remote: false
2531 });
2532
2533 if (!preset.name) {
2534 throw new AbortError(chalk`No preset header found. Cannot get name.`);
2535 }
2536
2537 let preset2 = await Preset.getByName(this.env, preset.name);
2538
2539 if (!preset2) {
2540 throw new AbortError(chalk`No preset found with name {red ${preset.name}} on {blue ${this.env}}`);
2541 }
2542
2543 await preset2.downloadCode();
2544
2545 let tempfile = require("tempy").file;
2546
2547 let temp = tempfile({
2548 extension: `${this.env}.${preset.ext}`
2549 });
2550 fs.writeFileSync(temp, preset2.code);
2551 let ptr = `${file},${temp}`; //raw output returns "file1" "file2"
2552
2553 if (configObject.rawOutput) {
2554 if (args["only-new"]) return temp;else return ptr;
2555 } //standard diff
2556
2557
2558 argv.command = argv.command || "diff";
2559 await spawn(argv.command, [file, temp], {
2560 stdio: "inherit"
2561 });
2562 },
2563
2564 async unknown(arg$$1, args) {
2565 log(chalk`Unknown action {red ${arg$$1}} try '{white rally help preset}'`);
2566 }
2567
2568};
2569let rulesub = {
2570 async before(args) {
2571 this.env = args.env;
2572 if (!this.env) throw new AbortError("No env supplied");
2573 },
2574
2575 async $list(args) {
2576 log("Loading...");
2577 let rules = await Rule.getAll(this.env);
2578 if (configObject.rawOutput) return rules;
2579 log(chalk`{yellow ${rules.length}} rules on {green ${this.env}}.`);
2580 rules.arr.sort((a, b) => {
2581 return Number(a.data.attributes.updatedAt) - Number(b.data.attributes.updatedAt);
2582 });
2583
2584 for (let rule of rules) log(rule.chalkPrint());
2585 },
2586
2587 async $create(args) {
2588 let preset = await selectPreset();
2589 let passNext = await selectRule("'On Exit OK'");
2590 let errorNext = await selectRule("'On Exit Error'");
2591 let name$$1 = await askInput("Rule Name", "What is the rule name?");
2592 name$$1 = name$$1.replace("@", preset.name);
2593 let desc = await askInput("Description", "Enter a description.");
2594 let dynamicNexts = [];
2595 let next;
2596
2597 while (next = await selectRule("dynamic next")) {
2598 let name$$1 = await askInput("Key", "Key name for dynamic next");
2599 dynamicNexts.push({
2600 meta: {
2601 transition: name$$1
2602 },
2603 type: "workflowRules",
2604 name: next.name
2605 });
2606 }
2607
2608 let rule = new Rule({
2609 subProject: configObject.project
2610 });
2611 rule.name = name$$1;
2612 rule.description = desc;
2613 rule.relationships.preset = {
2614 data: {
2615 name: preset.name,
2616 type: "presets"
2617 }
2618 };
2619 if (errorNext) rule.relationships.errorNext = {
2620 data: {
2621 name: errorNext.name,
2622 type: "workflowRules"
2623 }
2624 };
2625 if (passNext) rule.relationships.passNext = {
2626 data: {
2627 name: passNext.name,
2628 type: "workflowRules"
2629 }
2630 };
2631
2632 if (dynamicNexts[0]) {
2633 rule.relationships.dynamicNexts = {
2634 data: dynamicNexts
2635 };
2636 }
2637
2638 rule.saveB();
2639 },
2640
2641 async unknown(arg$$1, args) {
2642 log(chalk`Unknown action {red ${arg$$1}} try '{white rally help rule}'`);
2643 }
2644
2645};
2646let jupytersub = {
2647 async before(args) {
2648 this.input = args._.shift() || "main.ipynb";
2649 this.output = args._.shift() || "main.py";
2650 },
2651
2652 async $build(args) {
2653 let cmd = `jupyter nbconvert --to python ${this.input} --TagRemovePreprocessor.remove_cell_tags={\"remove_cell\"} --output ${this.output} --TemplateExporter.exclude_markdown=True --TemplateExporter.exclude_input_prompt=True --TemplateExporter.exclude_output_prompt=True`.split(" ");
2654 log(chalk`Compiling GCR file {green ${this.input}} into {green ${this.output}} using jupyter...`);
2655
2656 try {
2657 let {
2658 timestr
2659 } = await spawn(cmd[0], cmd.slice(1));
2660 log(chalk`Complete in ~{green.bold ${timestr}}.`);
2661 } catch (e) {
2662 if (e.code !== "ENOENT") throw e;
2663 log(chalk`Cannot run the build command. Make sure that you have jupyter notebook installed.\n{green pip install jupyter}`);
2664 return;
2665 }
2666 }
2667
2668};
2669
2670async function categorizeString(str, defaultSubproject = undefined) {
2671 str = str.trim();
2672
2673 if (str.startsWith('"')) {
2674 str = str.slice(1, -1);
2675 }
2676
2677 let match;
2678
2679 if (match = /^(\w)-(\w{1,10})-(\d{1,10}):/.exec(str)) {
2680 if (match[1] === "P") {
2681 let ret = await Preset.getById(match[2], match[3]); //TODO modify for subproject a bit
2682
2683 return ret;
2684 } else if (match[1] === "R") {
2685 return await Rule.getById(match[2], match[3]);
2686 } else {
2687 return null;
2688 }
2689 } else if (match = /^([\w \/\\\-_]*)[\/\\]?silo\-(\w+)[\/\\]/.exec(str)) {
2690 try {
2691 switch (match[2]) {
2692 case "presets":
2693 return new Preset({
2694 path: str,
2695 subProject: match[1]
2696 });
2697
2698 case "rules":
2699 return new Rule({
2700 path: str,
2701 subProject: match[1]
2702 });
2703
2704 case "metadata":
2705 return await Preset.fromMetadata(str, match[1]);
2706 }
2707 } catch (e) {
2708 log(e);
2709 }
2710 } else {
2711 return null;
2712 }
2713}
2714
2715let tagsub = {
2716 async before(args) {
2717 this.env = args.env;
2718 if (!this.env) throw new AbortError("No env supplied");
2719 },
2720
2721 async $list(args) {
2722 log("Loading...");
2723 let tags = await Tag.getAll(this.env);
2724 if (configObject.rawOutput) return tags;
2725 log(chalk`{yellow ${tags.length}} tags on {green ${this.env}}.`);
2726 tags.arr.sort((a, b) => {
2727 return Number(a.data.attributes.updatedAt) - Number(b.data.attributes.updatedAt);
2728 });
2729
2730 for (let tag of tags) log(tag.chalkPrint());
2731 },
2732
2733 async $create(args) {
2734 return Tag.create(this.env, "testTag");
2735 }
2736
2737};
2738let supplysub = {
2739 async before(args) {
2740 this.env = args.env;
2741 if (!this.env) throw new AbortError("No env supplied");
2742 this.files = await getFilesFromArgs(args);
2743 },
2744
2745 //Calculate a supply chain based on a starting rule at the top of the stack
2746 async $calc(args) {
2747 let name$$1 = args._.shift();
2748
2749 let stopName = args._.shift();
2750
2751 if (!name$$1) {
2752 throw new AbortError("No starting rule or @ supplied");
2753 }
2754
2755 if (name$$1 === "@") {
2756 log(chalk`Silo clone started`);
2757 this.chain = new SupplyChain();
2758 this.chain.remote = args.env;
2759 } else {
2760 let rules = await Rule.getAll(this.env);
2761 let stop, start;
2762 start = rules.findByNameContains(name$$1);
2763 if (stopName) stop = rules.findByNameContains(stopName);
2764
2765 if (!start) {
2766 throw new AbortError(chalk`No starting rule found by name {blue ${name$$1}}`);
2767 }
2768
2769 log(chalk`Analzying supply chain: ${start.chalkPrint(false)} - ${stop ? stop.chalkPrint(false) : "(open)"}`);
2770 this.chain = new SupplyChain(start, stop);
2771 }
2772
2773 await this.chain.calculate();
2774 return await this.postAction(args);
2775 },
2776
2777 async postAction(args) {
2778 //Now that we ahve a supply chain object, do something with it
2779 if (args["to"]) {
2780 this.chain.log();
2781
2782 if (this.chain.presets.arr[0]) {
2783 await this.chain.downloadPresetCode(this.chain.presets);
2784 log("Done");
2785 }
2786
2787 if (Array.isArray(args["to"])) {
2788 for (let to of args["to"]) {
2789 await this.chain.syncTo(to);
2790 }
2791 } else {
2792 await this.chain.syncTo(args["to"]);
2793 }
2794 } else if (args["diff"]) {
2795 //Very basic diff
2796 let env = args["diff"];
2797 await Promise.all(this.chain.presets.arr.map(obj => obj.downloadCode()));
2798 await Promise.all(this.chain.presets.arr.map(obj => obj.resolve()));
2799 let otherPresets = await Promise.all(this.chain.presets.arr.map(obj => Preset.getByName(env, obj.name)));
2800 otherPresets = new Collection(otherPresets.filter(x => x));
2801 await Promise.all(otherPresets.arr.map(obj => obj.downloadCode()));
2802 await Promise.all(otherPresets.arr.map(obj => obj.resolve()));
2803
2804 const printPresets = (preset, otherPreset) => {
2805 log(preset.chalkPrint(true));
2806
2807 if (otherPreset.name) {
2808 log(otherPreset.chalkPrint(true));
2809 } else {
2810 log(chalk`{red (None)}`);
2811 }
2812 };
2813
2814 for (let preset of this.chain.presets) {
2815 let otherPreset = otherPresets.arr.find(x => x.name === preset.name) || {};
2816
2817 if (preset.code === otherPreset.code) {
2818 if (!args["ignore-same"]) {
2819 printPresets(preset, otherPreset);
2820 log("Code Same");
2821 }
2822 } else {
2823 printPresets(preset, otherPreset);
2824
2825 if (args["ignore-same"]) {
2826 log("-------");
2827 } else {
2828 log("Code Different");
2829 }
2830 }
2831 }
2832 } else {
2833 return await this.chain.log();
2834 }
2835 },
2836
2837 async $make(args) {
2838 let set = new Set();
2839 let hints = args.hint ? Array.isArray(args.hint) ? args.hint : [args.hint] : []; //TODO modify for better hinting, and add this elsewhere
2840
2841 for (let hint of hints) {
2842 if (hint === "presets-uat") {
2843 log("got hint");
2844 await Preset.getAll("UAT");
2845 }
2846 }
2847
2848 for (let file of this.files) {
2849 set.add((await categorizeString(file)));
2850 }
2851
2852 let files = [...set];
2853 files = files.filter(f => f && !f.missing);
2854 this.chain = new SupplyChain();
2855 this.chain.rules = new Collection(files.filter(f => f instanceof Rule));
2856 this.chain.presets = new Collection(files.filter(f => f instanceof Preset));
2857 this.chain.notifications = new Collection([]);
2858 return await this.postAction(args);
2859 },
2860
2861 async unknown(arg$$1, args) {
2862 log(chalk`Unknown action {red ${arg$$1}} try '{white rally help supply}'`);
2863 }
2864
2865};
2866
2867function subCommand(object) {
2868 object = {
2869 before() {},
2870
2871 after() {},
2872
2873 unknown() {},
2874
2875 ...object
2876 };
2877 return async function (args) {
2878 //Grab the next arg on the stack, find a function tied to it, and run
2879 let arg$$1 = args._.shift();
2880
2881 let key = "$" + arg$$1;
2882 let ret;
2883
2884 if (object[key]) {
2885 await object.before(args);
2886 ret = await object[key](args);
2887 await object.after(args);
2888 } else {
2889 if (arg$$1 === undefined) arg$$1 = "(None)";
2890 object.unknown(arg$$1, args);
2891 }
2892
2893 return ret;
2894 };
2895}
2896
2897let cli = (_dec = helpText(`Display the help menu`), _dec2 = usage(`rally help [subhelp]`), _dec3 = param("subhelp", "The name of the command to see help for"), _dec4 = helpText("Rally tools jupyter interface. Requires jupyter to be installed."), _dec5 = usage("rally jupyter build [in] [out]"), _dec6 = param("in/out", "input and output file for jupyter. By default main.ipyrb and main.py"), _dec7 = helpText(`Preset related actions`), _dec8 = usage(`rally preset [action] --env <enviornment> --file [file1] --file [file2] ...`), _dec9 = param("action", "The action to perform. Can be upload, diff, list"), _dec10 = arg("-e", "--env", "The enviornment you wish to perform the action on"), _dec11 = arg("-f", "--file", "A file to act on"), _dec12 = arg("~", "--command", "If the action is diff, this is the command to run instead of diff"), _dec13 = helpText(`Rule related actions`), _dec14 = usage(`rally rule [action] --env [enviornment]`), _dec15 = param("action", "The action to perform. Only list is supported right now"), _dec16 = arg("-e", "--env", "The enviornment you wish to perform the action on"), _dec17 = helpText(`supply chain related actions`), _dec18 = usage(`rally supply [action] [identifier] --env [enviornment]`), _dec19 = param("action", "The action to perform. Can be calc."), _dec20 = param("identifier", "If the action is calc, then this identifier should be the first rule in the chain."), _dec21 = arg("-e", "--env", "The enviornment you wish to perform the action on"), _dec22 = helpText(`tags stuff`), _dec23 = usage(`rally tags [action]`), _dec24 = param("action", "The action to perform. Can be list or create."), _dec25 = arg("-e", "--env", "The enviornment you wish to perform the action on"), _dec26 = helpText(`List all available providers, or find one by name/id`), _dec27 = usage(`rally providers [identifier] --env [env] --raw`), _dec28 = param("identifier", "Either the name or id of the provider"), _dec29 = arg("-e", "--env", "The enviornment you wish to perform the action on"), _dec30 = arg("~", "--raw", "Raw output of command. If [identifier] is given, then print editorConfig too"), _dec31 = helpText(`Change config for rally tools`), _dec32 = usage("rally config [key] --set [value] --raw"), _dec33 = param("key", chalk`Key you want to edit. For example, {green chalk} or {green api.DEV}`), _dec34 = arg("~", "--set", "If this value is given, no interactive prompt will launch and the config option will change."), _dec35 = arg("~", "--raw", "Raw output of json config"), _dec36 = helpText(`create/modify asset`), _dec37 = usage("rally asset [action] [action...]"), _dec38 = param("action", chalk`Options are create, delete, launch, addfile. You can supply multiple actions to chain them`), _dec39 = arg(`-i`, `--id`, chalk`MOVIE_ID of asset to select`), _dec40 = arg(`-n`, `--name`, chalk`MOVIE_NAME of asset. with {white create}, '{white #}' will be replaced with a uuid. Default is '{white TEST_#}'`), _dec41 = arg(`-j`, `--job-name`, chalk`Job name to start (used with launch)`), _dec42 = arg(`~`, `--init-data`, chalk`Init data to use when launching job. can be string, or {white @path/to/file} for a file`), _dec43 = arg(`~`, `--file-label`, chalk`File label (used with addfile)`), _dec44 = arg(`~`, `--file-uri`, chalk`File s3 uri. Can use multiple uri's for the same label (used with addfile)`), (_obj = {
2898 async help(args) {
2899 let arg$$1 = args._.shift();
2900
2901 if (arg$$1) {
2902 let help = helpEntries[arg$$1];
2903
2904 if (!help) {
2905 log(chalk`No help found for '{red ${arg$$1}}'`);
2906 } else {
2907 log(printHelp(helpEntries[arg$$1]));
2908 }
2909 } else {
2910 for (let helpArg in helpEntries) {
2911 log(printHelp(helpEntries[helpArg], true));
2912 }
2913 }
2914 },
2915
2916 async jupyter(args) {
2917 return subCommand(jupytersub)(args);
2918 },
2919
2920 //@helpText(`Print input args, for debugging`)
2921 async printArgs(args) {
2922 log(args);
2923 },
2924
2925 async preset(args) {
2926 return subCommand(presetsub)(args);
2927 },
2928
2929 async rule(args) {
2930 return subCommand(rulesub)(args);
2931 },
2932
2933 async supply(args) {
2934 return subCommand(supplysub)(args);
2935 },
2936
2937 async tag(args) {
2938 return subCommand(tagsub)(args);
2939 },
2940
2941 async providers(args) {
2942 let env = args.env;
2943 if (!env) return errorLog("No env supplied.");
2944
2945 let ident = args._.shift();
2946
2947 let providers = await Provider.getAll(env);
2948
2949 if (ident) {
2950 let pro = providers.arr.find(x => x.id == ident || x.name.includes(ident));
2951
2952 if (!pro) {
2953 log(chalk`Couldn't find provider by {green ${ident}}`);
2954 } else {
2955 log(pro.chalkPrint(false));
2956 let econfig = await pro.getEditorConfig();
2957
2958 if (args.raw) {
2959 return pro;
2960 } else {
2961 if (econfig.helpText.length > 100) {
2962 econfig.helpText = "<too long to display>";
2963 }
2964
2965 if (econfig.completions.length > 5) {
2966 econfig.completions = "<too long to display>";
2967 }
2968
2969 log(econfig);
2970 }
2971 }
2972 } else {
2973 if (args.raw) return providers;
2974
2975 for (let pro of providers) log(pro.chalkPrint());
2976 }
2977 },
2978
2979 async config(args) {
2980 let prop = args._.shift();
2981
2982 let propArray = prop && prop.split("."); //if(!await configHelpers.askQuestion(`Would you like to create a new config file in ${configFile}`)) return;
2983
2984 let newConfigObject;
2985
2986 if (!prop) {
2987 if (configObject.rawOutput) return configObject;
2988 log("Creating new config");
2989 newConfigObject = { ...configObject
2990 };
2991
2992 for (let helperName in configHelpers) {
2993 if (helperName.startsWith("$")) {
2994 newConfigObject = { ...newConfigObject,
2995 ...(await configHelpers[helperName](false))
2996 };
2997 }
2998 }
2999 } else {
3000 log(chalk`Editing option {green ${prop}}`);
3001
3002 if (args.set) {
3003 newConfigObject = { ...configObject,
3004 [prop]: args.set
3005 };
3006 } else {
3007 let ident = "$" + propArray[0];
3008
3009 if (configHelpers[ident]) {
3010 newConfigObject = { ...configObject,
3011 ...(await configHelpers[ident](propArray))
3012 };
3013 } else {
3014 log(chalk`No helper for {red ${ident}}`);
3015 return;
3016 }
3017 }
3018 }
3019
3020 newConfigObject.hasConfig = true; //Create readable json and make sure the user is ok with it
3021
3022 let newConfig = JSON.stringify(newConfigObject, null, 4);
3023 log(newConfig); //-y or --set will make this not prompt
3024
3025 if (!args.y && !args.set && !(await askQuestion("Write this config to disk?"))) return;
3026 fs.writeFileSync(configFile, newConfig, {
3027 mode: 0o600
3028 });
3029 log(chalk`Created file {green ${configFile}}.`);
3030 },
3031
3032 async asset(args) {
3033 function uuid(args) {
3034 const digits = 16;
3035 return String(Math.floor(Math.random() * Math.pow(10, digits))).padStart(digits, "0");
3036 }
3037
3038 let name$$1 = args.name || `TEST_#`;
3039 let env = args.env;
3040 let asset;
3041
3042 let arg$$1 = args._.shift();
3043
3044 if (!arg$$1) {
3045 throw new AbortError(chalk`Missing arguments: see {white 'rally help asset'}`);
3046 }
3047
3048 if (args.anon) {
3049 args._.unshift(arg$$1);
3050 } else if (arg$$1 == "create") {
3051 name$$1 = name$$1.replace("#", uuid());
3052 asset = await Asset.createNew(name$$1, env);
3053 } else {
3054 args._.unshift(arg$$1);
3055
3056 if (args.id) {
3057 asset = Asset.lite(args.id, env);
3058 } else {
3059 asset = await Asset.getByName(env, args.name);
3060 }
3061 }
3062
3063 if (!asset && !args.anon) {
3064 throw new AbortError("No asset found/created");
3065 }
3066
3067 let launchArg = 0;
3068 let fileArg = 0;
3069
3070 let arrayify = (obj, i) => Array.isArray(obj) ? obj[i] : i == 0 ? obj : undefined;
3071
3072 while (arg$$1 = args._.shift()) {
3073 if (arg$$1 === "launch") {
3074 let initData = arrayify(args["init-data"], launchArg);
3075
3076 if (initData && initData.startsWith("@")) {
3077 log(chalk`Reading init data from {white ${initData.slice(1)}}`);
3078 initData = fs.readFileSync(initData.slice(1), "utf-8");
3079 }
3080
3081 let jobName = arrayify(args["job-name"], launchArg);
3082 let p = await Rule.getByName(env, jobName);
3083
3084 if (!p) {
3085 throw new AbortError(`Cannot launch job ${jobName}, does not exist (?)`);
3086 } else {
3087 log(chalk`Launching ${p.chalkPrint(false)} on ${asset ? asset.chalkPrint(false) : "(None)"}`);
3088 }
3089
3090 if (asset) {
3091 await asset.startWorkflow(jobName, initData);
3092 } else {
3093 await Asset.startAnonWorkflow(env, jobName, initData);
3094 }
3095
3096 launchArg++;
3097 } else if (arg$$1 === "addfile") {
3098 let label = arrayify(args["file-label"], fileArg);
3099 let uri = arrayify(args["file-uri"], fileArg);
3100
3101 if (label === undefined || !uri) {
3102 throw new AbortError("Number of file-label and file-uri does not match");
3103 }
3104
3105 await asset.addFile(label, uri);
3106 log(chalk`Added file ${label}`);
3107 fileArg++;
3108 } else if (arg$$1 === "delete") {
3109 await asset.delete();
3110 } else if (arg$$1 === "create") {
3111 throw new AbortError(`Cannot have more than 1 create/get per asset call`);
3112 } else if (arg$$1 === "show") {
3113 log(asset);
3114 }
3115 }
3116
3117 if (configObject.rawOutput) return asset;
3118 },
3119
3120 async checkSegments(args) {
3121 let asset = args._.shift();
3122
3123 let res = await lib.makeAPIRequest({
3124 env: args.env,
3125 path: `/movies/${asset}/metadata/Metadata`
3126 });
3127 let segments = res.data.attributes.metadata.userMetaData.segments.segments;
3128 let r = segments.reduce((lastSegment, val, ind) => {
3129 let curSegment = val.startTime;
3130
3131 if (curSegment < lastSegment) {
3132 log("bad segment " + (ind + 1));
3133 }
3134
3135 return val.endTime;
3136 }, "00:00:00:00");
3137 },
3138
3139 async listAssets(args, tag) {
3140 let req = await lib.indexPathFast({
3141 env: args.env,
3142 path: "/assets",
3143 qs: {
3144 noRelationships: true,
3145 sort: "id"
3146 },
3147 chunksize: 30
3148 });
3149
3150 for (let asset of req) {
3151 log(asset.id);
3152 }
3153
3154 return req;
3155 },
3156
3157 async listSegments(args) {
3158 let f = JSON.parse(fs.readFileSync(args.file, "utf-8"));
3159
3160 for (let asset of f) {
3161 var _r$data$attributes$me, _r$data$attributes$me2;
3162
3163 let r = await lib.makeAPIRequest({
3164 env: args.env,
3165 path: `/movies/${asset.id}/metadata/Metadata`
3166 });
3167 let segs = (_r$data$attributes$me = r.data.attributes.metadata.userMetaData) === null || _r$data$attributes$me === void 0 ? void 0 : (_r$data$attributes$me2 = _r$data$attributes$me.segments) === null || _r$data$attributes$me2 === void 0 ? void 0 : _r$data$attributes$me2.segments;
3168
3169 if (segs && segs.length > 1) {
3170 log(asset.id);
3171 log(asset.name);
3172 }
3173 }
3174 },
3175
3176 async test2(args) {
3177 let wfr = await lib.indexPath({
3178 env: args.env,
3179 path: "/workflowRuleMetadata"
3180 });
3181 log(wfr);
3182
3183 for (let wfrm of wfr) {
3184 try {
3185 wfrm.id = undefined;
3186 wfrm.links = undefined;
3187 log(wfrm);
3188 let req = await lib.makeAPIRequest({
3189 env: "DEV",
3190 path: "/workflowRuleMetadata",
3191 method: "POST",
3192 payload: {
3193 data: wfrm
3194 }
3195 });
3196 } catch (e) {
3197 log("caught");
3198 } //break;
3199
3200 }
3201 },
3202
3203 async test3(args) {
3204 let wfr = await lib.indexPath({
3205 env: args.env,
3206 path: "/workflowRuleMetadata"
3207 });
3208 log(wfr);
3209
3210 for (let wfrm of wfr) {
3211 try {
3212 wfrm.id = undefined;
3213 wfrm.links = undefined;
3214 log(wfrm);
3215 let req = await lib.makeAPIRequest({
3216 env: "DEV",
3217 path: "/workflowRuleMetadata",
3218 method: "POST",
3219 payload: {
3220 data: wfrm
3221 }
3222 });
3223 } catch (e) {
3224 log("caught");
3225 } //break;
3226
3227 }
3228 },
3229
3230 sleep(time = 1000) {
3231 return new Promise(resolve => setTimeout(resolve, time));
3232 },
3233
3234 async audit(args) {
3235 let supportedAudits = ["presets", "rule", "other"];
3236 await addAutoCompletePrompt();
3237 let q = await inquirer.prompt([{
3238 type: "autocomplete",
3239 name: "obj",
3240 message: `What audit do you want?`,
3241 source: async (sofar, input) => {
3242 return supportedAudits.filter(x => input ? x.includes(input.toLowerCase()) : true);
3243 }
3244 }]);
3245 let choice = q.obj;
3246 let resourceId = undefined;
3247
3248 let filterFunc = _ => _;
3249
3250 if (choice === "presets") {
3251 let preset = await selectPreset();
3252 let remote = await Preset.getByName(args.env, preset.name);
3253 if (!remote) throw new AbortError("Could not find this item on remote env");
3254
3255 filterFunc = ev => ev.resource == "Preset";
3256
3257 resourceId = remote.id;
3258 } else if (choice === "rule") {
3259 let preset = await selectRule();
3260 let remote = await Rule.getByName(args.env, preset.name);
3261 if (!remote) throw new AbortError("Could not find this item on remote env");
3262
3263 filterFunc = ev => ev.resource == "Rule";
3264
3265 resourceId = remote.id;
3266 } else {
3267 resourceId = await askInput(null, "What resourceID?");
3268 }
3269
3270 log(chalk`Resource ID on {blue ${args.env}} is {yellow ${resourceId}}`);
3271 log(`Loading audits (this might take a while)`);
3272 const numRows = 100;
3273 let r = await lib.makeAPIRequest({
3274 env: args.env,
3275 path: `/v1.0/audit?perPage=${numRows}&count=${numRows}&filter=%7B%22resourceId%22%3A%22${resourceId}%22%7D&autoload=false&pageNum=1&include=`,
3276 timeout: 180000
3277 });
3278 r.data = r.data.filter(filterFunc);
3279 log("Data recieved, parsing users");
3280
3281 for (let event of r.data) {
3282 var _event$correlation;
3283
3284 let uid = event === null || event === void 0 ? void 0 : (_event$correlation = event.correlation) === null || _event$correlation === void 0 ? void 0 : _event$correlation.userId;
3285 if (!uid) continue;
3286
3287 try {
3288 event.user = await User.getById(args.env, uid);
3289 } catch (e) {
3290 event.user = {
3291 name: "????"
3292 };
3293 }
3294 }
3295
3296 if (args.raw) return r.data;
3297 let evCounter = 0;
3298
3299 for (let event of r.data) {
3300 var _event$user;
3301
3302 let evtime = moment(event.createdAt);
3303 let date = evtime.format("ddd YYYY/MM/DD hh:mm:ssa");
3304 let timedist = evtime.fromNow();
3305 log(chalk`${date} {yellow ${timedist}} {green ${(_event$user = event.user) === null || _event$user === void 0 ? void 0 : _event$user.name}} ${event.event}`);
3306 if (++evCounter >= 30) break;
3307 }
3308 },
3309
3310 async audit2(args) {
3311 const numRows = 1000;
3312 let r = await lib.makeAPIRequest({
3313 env: args.env,
3314 //path: `/v1.0/audit?perPage=${numRows}&count=${numRows}&autoload=false&pageNum=1&include=`,
3315 path: `/v1.0/audit?perPage=${numRows}&count=${numRows}&filter=%7B%22correlation.userId%22%3A%5B%22164%22%5D%7D&autoload=false&pageNum=1&include=`,
3316 timeout: 60000
3317 });
3318
3319 for (let event of r.data) {
3320 log(event.event);
3321 }
3322 },
3323
3324 async findIDs(args) {
3325 let files = await getFilesFromArgs(args);
3326
3327 for (let file of files) {
3328 let preset = await Preset.getByName(args.env, file);
3329 await preset.resolve();
3330 log(`silo-presets/${file}.${preset.ext}`);
3331 }
3332 },
3333
3334 async getAssets(env, name$$1) {
3335 if (!this.callid) this.callid = 0;
3336 this.callid++;
3337 let callid = this.callid;
3338 await this.sleep(500);
3339 if (callid != this.callid) return this.lastResult || [];
3340 let req = await lib.makeAPIRequest({
3341 env,
3342 path: `/assets`,
3343 qs: name$$1 ? {
3344 filter: `nameContains=${name$$1}`
3345 } : undefined
3346 });
3347 this.lastCall = Date.now();
3348 return this.lastResult = req.data;
3349 },
3350
3351 async content(args) {
3352 addAutoCompletePrompt();
3353 let q = await inquirer.prompt([{
3354 type: "autocomplete",
3355 name: "what",
3356 message: `What asset do you want?`,
3357 source: async (sofar, input) => {
3358 let assets = await this.getAssets(args.env, input);
3359 assets = assets.map(x => new Asset({
3360 data: x,
3361 remote: args.env
3362 }));
3363 return assets.map(x => ({
3364 name: x.chalkPrint(true) + ": " + x.data.links.self.replace("/api/v2/assets/", "/content/"),
3365 value: x
3366 }));
3367 }
3368 }]);
3369 },
3370
3371 async ["@"](args) {
3372 args._.unshift("-");
3373
3374 args._.unshift("make");
3375
3376 return this.supply(args);
3377 },
3378
3379 async test(args) {
3380 let asset = await Asset.getByName("UAT", args.name);
3381 log(asset);
3382 },
3383
3384 //Used to test startup and teardown speed.
3385 noop() {
3386 return true;
3387 }
3388
3389}, (_applyDecoratedDescriptor(_obj, "help", [_dec, _dec2, _dec3], Object.getOwnPropertyDescriptor(_obj, "help"), _obj), _applyDecoratedDescriptor(_obj, "jupyter", [_dec4, _dec5, _dec6], Object.getOwnPropertyDescriptor(_obj, "jupyter"), _obj), _applyDecoratedDescriptor(_obj, "preset", [_dec7, _dec8, _dec9, _dec10, _dec11, _dec12], Object.getOwnPropertyDescriptor(_obj, "preset"), _obj), _applyDecoratedDescriptor(_obj, "rule", [_dec13, _dec14, _dec15, _dec16], Object.getOwnPropertyDescriptor(_obj, "rule"), _obj), _applyDecoratedDescriptor(_obj, "supply", [_dec17, _dec18, _dec19, _dec20, _dec21], Object.getOwnPropertyDescriptor(_obj, "supply"), _obj), _applyDecoratedDescriptor(_obj, "tag", [_dec22, _dec23, _dec24, _dec25], Object.getOwnPropertyDescriptor(_obj, "tag"), _obj), _applyDecoratedDescriptor(_obj, "providers", [_dec26, _dec27, _dec28, _dec29, _dec30], Object.getOwnPropertyDescriptor(_obj, "providers"), _obj), _applyDecoratedDescriptor(_obj, "config", [_dec31, _dec32, _dec33, _dec34, _dec35], Object.getOwnPropertyDescriptor(_obj, "config"), _obj), _applyDecoratedDescriptor(_obj, "asset", [_dec36, _dec37, _dec38, _dec39, _dec40, _dec41, _dec42, _dec43, _dec44], Object.getOwnPropertyDescriptor(_obj, "asset"), _obj)), _obj));
3390
3391async function unknownCommand(cmd) {
3392 log(chalk`Unknown command {red ${cmd}}.`);
3393}
3394
3395async function noCommand() {
3396 write(chalk`
3397Rally Tools {yellow v${version} (alpha)} CLI
3398by John Schmidt <John_Schmidt@discovery.com>
3399`); //Prompt users to setup one time config.
3400
3401 if (!configObject.hasConfig) {
3402 write(chalk`
3403It looks like you haven't setup the config yet. Please run '{green rally config}'.
3404`);
3405 return;
3406 } //API Access tests
3407
3408
3409 for (let env of ["LOCAL", "DEV", "UAT", "QA", "PROD"]) {
3410 //Test access. Returns HTTP response code
3411 let resultStr;
3412
3413 try {
3414 let result = await rallyFunctions.testAccess(env); //Create a colored display and response
3415
3416 resultStr = chalk`{yellow ${result} <unknown>}`;
3417 if (result === 200) resultStr = chalk`{green 200 OK}`;else if (result === 401) resultStr = chalk`{red 401 No Access}`;else if (result >= 500) resultStr = chalk`{yellow ${result} API Down?}`;else if (result === true) resultStr = chalk`{green OK}`;else if (result === false) resultStr = chalk`{red BAD}`;
3418 } catch (e) {
3419 if (e instanceof UnconfiguredEnvError) {
3420 resultStr = chalk`{yellow Unconfigured}`;
3421 } else if (e instanceof APIError) {
3422 if (!e.response.body) {
3423 resultStr = chalk`{red Timeout (?)}`;
3424 }
3425 } else if (e.name == "RequestError") {
3426 resultStr = chalk`{red Low level error (check internet): ${e.error.errno}}`;
3427 } else {
3428 throw e;
3429 }
3430 }
3431
3432 log(chalk` ${env}: ${resultStr}`);
3433 }
3434}
3435
3436async function $main() {
3437 //Supply --config to load a different config file
3438 if (argv.config) loadConfig(argv.config); // First we need to decide if the user wants color or not. If they do want
3439 // color, we need to make sure we use the right mode
3440
3441 chalk.enabled = configObject.hasConfig ? configObject.chalk : true;
3442
3443 if (chalk.level === 0 || !chalk.enabled) {
3444 let force = argv["force-color"];
3445
3446 if (force) {
3447 chalk.enabled = true;
3448
3449 if (force === true && chalk.level === 0) {
3450 chalk.level = 1;
3451 } else if (Number(force)) {
3452 chalk.level = Number(force);
3453 }
3454 }
3455 } //This flag being true allows you to modify UAT and PROD
3456
3457
3458 if (!argv["protect"]) {
3459 configObject.dangerModify = true;
3460 } //This enables raw output for some functions
3461
3462
3463 if (argv["raw"]) {
3464 configObject.rawOutput = true;
3465
3466 global.log = () => {};
3467
3468 global.errorLog = () => {};
3469
3470 global.write = () => {};
3471 }
3472
3473 if (argv["ignore-missing"]) {
3474 configObject.ignoreMissing = true;
3475 } //Default enviornment should normally be from config, but it can be
3476 //overridden by the -e/--env flag
3477
3478
3479 if (configObject.defaultEnv) {
3480 argv.env = argv.env || configObject.defaultEnv;
3481 } //Enable verbose logging in some places.
3482
3483
3484 if (argv["vverbose"]) {
3485 configObject.verbose = argv["vverbose"];
3486 configObject.vverbose = true;
3487 } else if (argv["verbose"]) {
3488 configObject.verbose = argv["verbose"];
3489 } else if (argv["vvverbose"]) {
3490 configObject.verbose = true;
3491 configObject.vverbose = true;
3492 configObject.vvverbose = true;
3493 } //copy argument array to new object to allow modification
3494
3495
3496 argv._old = argv._.slice(); //Take first argument after `node bundle.js`
3497 //If there is no argument, display the default version info and API access.
3498
3499 let func = argv._.shift();
3500
3501 if (func) {
3502 if (!cli[func]) return await unknownCommand(func);
3503
3504 try {
3505 //Call the cli function
3506 let ret = await cli[func](argv);
3507
3508 if (ret) {
3509 write(chalk.white("CLI returned: "));
3510 if (ret instanceof Collection) ret = ret.arr; //Directly use console.log so that --raw works as intended.
3511
3512 if (typeof ret === "object") {
3513 console.log(JSON.stringify(ret, null, 4));
3514 } else {
3515 console.log(ret);
3516 }
3517 }
3518 } catch (e) {
3519 if (e instanceof AbortError) {
3520 log(chalk`{red CLI Aborted}: ${e.message}`);
3521 } else {
3522 throw e;
3523 }
3524 }
3525 } else {
3526 await noCommand();
3527 }
3528}
3529
3530async function main$1(...args) {
3531 //Catch all for errors to avoid ugly default node promise catcher
3532 try {
3533 await $main(...args);
3534 } catch (e) {
3535 errorLog(e.stack);
3536 }
3537} // If this is an imported module, then we should exec the cli interface.
3538// Oterwise just export everything.
3539
3540
3541if (require.main === module) {
3542 main$1();
3543} else {
3544 module.exports = allIndexBundle;
3545}
3546//# sourceMappingURL=bundle.js.map