@codiac.io/codiac-cli 1.2.217 → 1.2.221
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/apis/codiac-api/gen/client.d.ts +4 -4
- package/dist/apis/codiac-api/gen/client.js +20 -19
- package/dist/apis/codiac-api/gen/client.js.map +1 -1
- package/dist/cli-common/command-base.d.ts +2 -0
- package/dist/cli-common/command-base.js +23 -8
- package/dist/cli-common/command-base.js.map +1 -1
- package/dist/codiac-constants.d.ts +10 -0
- package/dist/codiac-constants.js +10 -0
- package/dist/codiac-constants.js.map +1 -1
- package/dist/commands/config/add.d.ts +34 -22
- package/dist/commands/config/add.js +321 -209
- package/dist/commands/config/add.js.map +1 -1
- package/dist/commands/config/delete.d.ts +22 -5
- package/dist/commands/config/delete.js +270 -82
- package/dist/commands/config/delete.js.map +1 -1
- package/dist/commands/config/settings/get.d.ts +38 -0
- package/dist/commands/config/settings/get.js +297 -0
- package/dist/commands/config/settings/get.js.map +1 -0
- package/dist/uilogic/config-ui-utils.d.ts +112 -0
- package/dist/uilogic/config-ui-utils.js +574 -0
- package/dist/uilogic/config-ui-utils.js.map +1 -0
- package/dist/uilogic/enterprise-contextualizer.d.ts +6 -3
- package/dist/uilogic/enterprise-contextualizer.js +51 -21
- package/dist/uilogic/enterprise-contextualizer.js.map +1 -1
- package/oclif.manifest.json +331 -59
- package/package.json +2 -1
|
@@ -12,159 +12,120 @@ const command_base_enterprise_1 = require("../../command-base-enterprise");
|
|
|
12
12
|
const CodiacConstants = require("../../codiac-constants");
|
|
13
13
|
const path = require("path");
|
|
14
14
|
const render = require("../../uilogic/render-methods");
|
|
15
|
+
const config_ui_utils_1 = require("../../uilogic/config-ui-utils");
|
|
15
16
|
// const { selectFiles, COMPLETED, CANCELLED } = require('select-files-cli'); // gd js wo ts...
|
|
16
17
|
// const { selectFiles, COMPLETED, CANCELLED } = require('../../uilogic/file-selector'); // gd js wo ts...
|
|
17
18
|
/** The value provided as input that indicates
|
|
18
19
|
* a user's desire to be prompted with a list from which choose the value(s),
|
|
19
20
|
* instead of entering them manually or taking a default. */
|
|
20
21
|
exports.PROMPT_ME_DESIGNATOR = "?";
|
|
22
|
+
/** Reads the given stream directly without assigning listeners to its events. */
|
|
23
|
+
function read(stream) {
|
|
24
|
+
var _a, stream_1, stream_1_1;
|
|
25
|
+
var _b, e_1, _c, _d;
|
|
26
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
27
|
+
try {
|
|
28
|
+
const chunks = [];
|
|
29
|
+
try {
|
|
30
|
+
for (_a = true, stream_1 = tslib_1.__asyncValues(stream); stream_1_1 = yield stream_1.next(), _b = stream_1_1.done, !_b;) {
|
|
31
|
+
_d = stream_1_1.value;
|
|
32
|
+
_a = false;
|
|
33
|
+
try {
|
|
34
|
+
const chunk = _d;
|
|
35
|
+
chunks.push(chunk);
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
_a = true;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
43
|
+
finally {
|
|
44
|
+
try {
|
|
45
|
+
if (!_a && !_b && (_c = stream_1.return)) yield _c.call(stream_1);
|
|
46
|
+
}
|
|
47
|
+
finally { if (e_1) throw e_1.error; }
|
|
48
|
+
}
|
|
49
|
+
const out = Buffer.concat(chunks).toString('utf8');
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
throw err;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
var InteractionModes;
|
|
58
|
+
(function (InteractionModes) {
|
|
59
|
+
InteractionModes["echo"] = "echo";
|
|
60
|
+
InteractionModes["toscript"] = "toscript";
|
|
61
|
+
InteractionModes["silent"] = "silent";
|
|
62
|
+
})(InteractionModes || (InteractionModes = {}));
|
|
21
63
|
class ConfigAdd extends command_base_enterprise_1.CommandBaseEnterprise {
|
|
64
|
+
constructor() {
|
|
65
|
+
super(...arguments);
|
|
66
|
+
/** CLI Command-line string to rerun this execution as a non-TTY script. */
|
|
67
|
+
this.cmd = ["cod", "config", "add", "--silent"];
|
|
68
|
+
}
|
|
69
|
+
// --------------------------------------------------------------------
|
|
70
|
+
// Lazy-loaded properties
|
|
71
|
+
get configUtils() {
|
|
72
|
+
if (this._configUtils_backer === undefined) {
|
|
73
|
+
this._configUtils_backer = this.ioc.get(config_ui_utils_1.ConfigUiUtils);
|
|
74
|
+
}
|
|
75
|
+
return this._configUtils_backer;
|
|
76
|
+
}
|
|
77
|
+
// --------------------------------------------------------------------
|
|
78
|
+
bootstrap() {
|
|
79
|
+
super.bootstrap();
|
|
80
|
+
this.ioc.bind(config_ui_utils_1.ConfigUiUtils).toSelf();
|
|
81
|
+
}
|
|
22
82
|
run() {
|
|
23
83
|
var _a;
|
|
24
84
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
25
85
|
try {
|
|
26
86
|
this.bootstrap();
|
|
27
|
-
|
|
87
|
+
yield this.readStdin();
|
|
28
88
|
(_a = this._relayContainer) === null || _a === void 0 ? void 0 : _a.ready$.subscribe((ready) => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
freehand prompt with "?" as default (enter "?" to browse)
|
|
70
|
-
enter rel path from container root (app root?)
|
|
71
|
-
|
|
72
|
-
3. Setting
|
|
73
|
-
select from existing
|
|
74
|
-
if file selected, merge and dim
|
|
75
|
-
(tree with "+newChild" at top of each branch) (How do you prevent selection of branch vs leaf?)
|
|
76
|
-
|
|
77
|
-
4. Scope ("Where will it apply?")
|
|
78
|
-
cabinet tree view with un-hydrated scopes dimmed, hydrated showing values
|
|
79
|
-
|
|
80
|
-
5. Value
|
|
81
|
-
(render pedigree)
|
|
82
|
-
default = flags.value ?? selectedFile.value ?? existing.value
|
|
83
|
-
|
|
84
|
-
6. Confirm or loop back around to enterprise
|
|
85
|
-
*/
|
|
86
|
-
// let cab = await this.establishCabinet(flags.cabinet, true);
|
|
87
|
-
// let configName = flags.file || CodiacConstants.DEFAULT_APP_SETTINGS_FILENAME;
|
|
88
|
-
// if (configName == PROMPT_ME_DESIGNATOR) {
|
|
89
|
-
// let confirmed = false;
|
|
90
|
-
// while (!confirmed) {
|
|
91
|
-
// // Step 1) select the distribution folder (aka: the build output folder)
|
|
92
|
-
// let folderOptions: FolderSelectionOptions = {
|
|
93
|
-
// root: this._projectRoot,
|
|
94
|
-
// startingPath: process.cwd(),
|
|
95
|
-
// };
|
|
96
|
-
// let distFolder = await this._ui.promptSelectFolder("distFolder", "Select the distribution folder (aka: the build output folder)...", folderOptions);
|
|
97
|
-
// // Step 2) select the config file within it.
|
|
98
|
-
// let options: FileSelectionOptions = {
|
|
99
|
-
// root: distFolder,
|
|
100
|
-
// startingPath: distFolder,
|
|
101
|
-
// extensions: ["json", "config", "yaml", "ini", "properties"],
|
|
102
|
-
// asRelative: true
|
|
103
|
-
// };
|
|
104
|
-
// configName = await this._ui.promptSelectFile("targetFile", "Select the target file...", options);
|
|
105
|
-
// confirmed = await this._ui.promptConfirm("targetFileCOnfirmation", `Target file: ${configName}`, true);
|
|
106
|
-
// }
|
|
107
|
-
// // this._ui.userMessage("Select the target file...")
|
|
108
|
-
// // let relativeTo = process.cwd();
|
|
109
|
-
// // let exts = ["json", "config", "yaml", "ini", "properties"];
|
|
110
|
-
// // let ptn = `\\.(${exts.join("|")})$`;
|
|
111
|
-
// // let rx = new RegExp(ptn, "i");
|
|
112
|
-
// // let options: any = {
|
|
113
|
-
// // multi: true,
|
|
114
|
-
// // clearConsole: false,
|
|
115
|
-
// // root: this._projectRoot
|
|
116
|
-
// // // fileFilter: (filename: string) => { return /\.(json|yaml|config|properties|ini)$/i.test(filename) } });
|
|
117
|
-
// // }
|
|
118
|
-
// // options.fileFilter = (fileName: string) => rx.test(fileName);
|
|
119
|
-
// // let fileResult = await selectFiles(options);
|
|
120
|
-
// // console.dir(fileResult);
|
|
121
|
-
// // if (fileResult.status == COMPLETED && fileResult.selectedFiles && fileResult.selectedFiles.length > 0) {
|
|
122
|
-
// // let selected = fileResult.selectedFiles[0];
|
|
123
|
-
// // let relPathName = path.relative(relativeTo, selected);
|
|
124
|
-
// // this._ui.userMessage(`Selected file: ${relPathName}`);
|
|
125
|
-
// // }
|
|
126
|
-
// }
|
|
127
|
-
// // 1 Get the list of available built in system settings
|
|
128
|
-
// // stub:
|
|
129
|
-
// this._appConfig = this._ops.loadConfig();
|
|
130
|
-
// let avails = await this.getAvailableSettings();
|
|
131
|
-
// // Prompt for setting if reqd
|
|
132
|
-
// let setting: string = args.setting || flags.setting;
|
|
133
|
-
// if (!setting) {
|
|
134
|
-
// let result = await inquirer.prompt({ type: 'list', name: 'setting', message: 'Setting to add:', choices: avails });
|
|
135
|
-
// setting = result.setting;
|
|
136
|
-
// }
|
|
137
|
-
// // this.log(result.setting);
|
|
138
|
-
// // PROMPT FOR VALUE (if reqd)
|
|
139
|
-
// let val: string;
|
|
140
|
-
// if (flags.value) {
|
|
141
|
-
// val = flags.value;
|
|
142
|
-
// } else {
|
|
143
|
-
// // TODO: this current value needs to support the scoped value set
|
|
144
|
-
// let currentValue = (this._appConfig) ? this._appConfig[setting] : undefined;
|
|
145
|
-
// let response = await inquirer.prompt({ type: 'input', name: 'settingValue', message: `Value for ${setting}: `, default: currentValue });
|
|
146
|
-
// val = response.settingValue;
|
|
147
|
-
// }
|
|
148
|
-
// if (flags.enterprise || flags.environment || flags.cabinet) {
|
|
149
|
-
// // WRITE SCOPED TO THE API
|
|
150
|
-
// let level: ScopeLevel = ScopeLevel.enterprise;
|
|
151
|
-
// let scopeName: string = "";
|
|
152
|
-
// if (flags.enterprise) {
|
|
153
|
-
// level = ScopeLevel.enterprise;
|
|
154
|
-
// scopeName = flags.enterprise;
|
|
155
|
-
// } else if (flags.environment) {
|
|
156
|
-
// level = ScopeLevel.environment;
|
|
157
|
-
// scopeName = flags.environment;
|
|
158
|
-
// } else if (flags.cabinet) {
|
|
159
|
-
// level = ScopeLevel.cabinet;
|
|
160
|
-
// scopeName = flags.cabinet;
|
|
161
|
-
// }
|
|
162
|
-
// this.writeSetting_Api(partialConfigDef.enterprise, partialConfigDef.asset, configName, setting, level, scopeName, val);
|
|
163
|
-
// } else {
|
|
164
|
-
// // WRITE UNSCOPED TO LOCAL
|
|
165
|
-
// this.writeSetting_local(setting, val);
|
|
166
|
-
// }
|
|
167
|
-
// this.log(`Applied ${configName} setting "${setting}" = "${val}"`);
|
|
89
|
+
try {
|
|
90
|
+
// 0. SET DEFAULTS
|
|
91
|
+
this._userCntx = yield this.establishTenantContext(this._userCntx);
|
|
92
|
+
let enterprise = (yield this.establishEnterpriseContext()).enterprise;
|
|
93
|
+
// 1. CAPTURE ARGS
|
|
94
|
+
let [partial, interactionMode] = yield this.captureArgs(enterprise.code);
|
|
95
|
+
// 2. ACQUIRE INPUT
|
|
96
|
+
let rootMap = yield this.getRootMap(enterprise.code);
|
|
97
|
+
let candidate;
|
|
98
|
+
if (interactionMode == InteractionModes.silent) {
|
|
99
|
+
candidate = this.buildCandidate_silently(partial, rootMap);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
candidate = yield this.buildCandidate_interactively(partial, rootMap);
|
|
103
|
+
}
|
|
104
|
+
// In case we're hanging waiting for piped-in data that doesnt exist...
|
|
105
|
+
if (!process.stdin.destroyed)
|
|
106
|
+
process.stdin.destroy();
|
|
107
|
+
if (candidate == undefined) {
|
|
108
|
+
this.logger.notice(`Operation cancelled. No work was done.`);
|
|
109
|
+
this._ui.userMessage(`Operation cancelled. No work was done.`);
|
|
110
|
+
this.exit(0);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
// 3. RENDER COMMAND STRING
|
|
114
|
+
if (interactionMode != undefined && [InteractionModes.echo, InteractionModes.toscript].includes(interactionMode)) {
|
|
115
|
+
this.cmd = this.buildCommandString(candidate, this.cmd);
|
|
116
|
+
this._ui.userMessage(this.cmd.join(" "));
|
|
117
|
+
}
|
|
118
|
+
if (interactionMode != InteractionModes.toscript) {
|
|
119
|
+
// 4. EXECUTE THE MAIN TASK
|
|
120
|
+
yield this.executeTask(candidate);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
this.handleError(err);
|
|
127
|
+
// dont rethrow - err handling in the observable isnt yet user-friendly.
|
|
128
|
+
}
|
|
168
129
|
}));
|
|
169
130
|
}
|
|
170
131
|
catch (err) {
|
|
@@ -173,11 +134,149 @@ class ConfigAdd extends command_base_enterprise_1.CommandBaseEnterprise {
|
|
|
173
134
|
}
|
|
174
135
|
});
|
|
175
136
|
}
|
|
176
|
-
|
|
137
|
+
captureArgs(currentEnterprise) {
|
|
138
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
177
139
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
140
|
+
// TODO: Move this into the base class
|
|
141
|
+
const { args, flags } = yield this.parse(ConfigAdd);
|
|
142
|
+
// TODO: Consider making this parse a separate abstract base method
|
|
143
|
+
// stdin
|
|
144
|
+
let inputDoc;
|
|
145
|
+
if (this.pipedInput) {
|
|
146
|
+
inputDoc = this.configUtils.parseInputString(this.pipedInput.trim());
|
|
147
|
+
this._ui.userMessage(`Found ${inputDoc.length} record(s) to add in the stdin pipeline.`);
|
|
148
|
+
}
|
|
149
|
+
let partial = { enterprise: currentEnterprise };
|
|
150
|
+
partial.asset = flags.asset;
|
|
151
|
+
if (flags.type) {
|
|
152
|
+
partial.configType = Object.values(config_ui_utils_1.SpecialConfigTypes).find(x => x.toString() == flags.type);
|
|
153
|
+
if (partial.configType == undefined)
|
|
154
|
+
delete partial.configType;
|
|
155
|
+
}
|
|
156
|
+
else if (flags.file) {
|
|
157
|
+
partial.targetFile = flags.file;
|
|
158
|
+
}
|
|
159
|
+
partial.scope =
|
|
160
|
+
(_b = (_a = (flags['enterprise-scope'] ? codiac_relay_contracts_1.ScopeLevel.enterprise : undefined)) !== null && _a !== void 0 ? _a : (flags.enviro ? codiac_relay_contracts_1.ScopeLevel.environment : undefined)) !== null && _b !== void 0 ? _b : (flags.cabinet ? codiac_relay_contracts_1.ScopeLevel.cabinet : undefined);
|
|
161
|
+
partial.target =
|
|
162
|
+
(_d = (_c = (flags['enterprise-scope'] ? partial.enterprise : undefined)) !== null && _c !== void 0 ? _c : flags.enviro) !== null && _d !== void 0 ? _d : flags.cabinet;
|
|
163
|
+
if (flags.setting) {
|
|
164
|
+
partial.settings = [{ setting: flags.setting, value: flags.value }];
|
|
165
|
+
}
|
|
166
|
+
if (inputDoc != undefined) {
|
|
167
|
+
partial.settings = ((_e = partial.settings) !== null && _e !== void 0 ? _e : []).concat(inputDoc);
|
|
168
|
+
}
|
|
169
|
+
// partial.description = flags.description;
|
|
170
|
+
// TODO: move this into the base class
|
|
171
|
+
const interactionMode = (this.pipedInput) ? InteractionModes.silent : (_g = (_f = undefined !== null && undefined !== void 0 ? undefined : (flags.echo ? InteractionModes.echo : undefined)) !== null && _f !== void 0 ? _f : (flags["to-script"] ? InteractionModes.toscript : undefined)) !== null && _g !== void 0 ? _g : (flags.silent ? InteractionModes.silent : undefined);
|
|
172
|
+
return [partial, interactionMode];
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
parseTable(input, separator = ",") {
|
|
176
|
+
let output = [];
|
|
177
|
+
let lines = input
|
|
178
|
+
.split("\n")
|
|
179
|
+
.map(x => x.trim());
|
|
180
|
+
lines.shift();
|
|
181
|
+
lines.forEach(x => {
|
|
182
|
+
let parts = x.split(",").map(x => x.trim());
|
|
183
|
+
output.push({ setting: parts[0], value: parts[1] });
|
|
184
|
+
});
|
|
185
|
+
return output;
|
|
186
|
+
}
|
|
187
|
+
buildCandidate_silently(partial, rootMap) {
|
|
188
|
+
var _a;
|
|
189
|
+
try {
|
|
190
|
+
// VALIDATE / SET DEFAULTS
|
|
191
|
+
if (partial.asset == undefined || _.isEmpty(partial.asset))
|
|
192
|
+
throw new Error(`Invalid input: missing asset name.`);
|
|
193
|
+
if (partial.enterprise == undefined || _.isEmpty(partial.enterprise)) {
|
|
194
|
+
// Derive the one OR throw if it's indeterminate
|
|
195
|
+
let assetParents = rootMap.enterprises.filter(e => e.assets.find(a => a.name == partial.asset));
|
|
196
|
+
if (assetParents.length == 1) {
|
|
197
|
+
partial.enterprise = assetParents[0].name;
|
|
198
|
+
}
|
|
199
|
+
else if (assetParents.length > 1) {
|
|
200
|
+
throw new Error(`Invalid input: missing enterprise.`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (partial.targetFile == undefined && partial.configType == undefined)
|
|
204
|
+
throw new Error("Invalid input: Must specify the file or type.");
|
|
205
|
+
// Validate scope/target
|
|
206
|
+
if (partial.scope == undefined || _.isEmpty(partial.scope)) {
|
|
207
|
+
throw new Error(`Invalid input: scope required. Please set --enterprise-scope, --enviro, or --cabinet.`);
|
|
208
|
+
}
|
|
209
|
+
else if (!(Object.keys(codiac_relay_contracts_1.ScopeLevel)).includes(partial.scope)) {
|
|
210
|
+
throw new Error(`Invalid input: invalid scope level. Please set --enterprise-scope, --enviro, or --cabinet.`);
|
|
211
|
+
}
|
|
212
|
+
if (partial.scope == codiac_relay_contracts_1.ScopeLevel.enterprise) {
|
|
213
|
+
// This code should never get reached. Its just here for completeness.
|
|
214
|
+
if ((partial.target != undefined || _.isEmpty(partial.target)) && (partial.target != partial.enterprise))
|
|
215
|
+
throw new Error(`Invalid input: scope target for enterprise scope should match the enterprise.`);
|
|
216
|
+
}
|
|
217
|
+
else if (partial.target == undefined || _.isEmpty(partial.target)) {
|
|
218
|
+
throw new Error(`Invalid input: missing scope target. Please set --enterprise-scope, --enviro, or --cabinet.`);
|
|
219
|
+
}
|
|
220
|
+
else if ((0, config_ui_utils_1.findScopeTarget)(rootMap, partial.scope, partial.target) == undefined) {
|
|
221
|
+
throw new Error(`Invalid input: the given ${partial.scope} was not found.`);
|
|
222
|
+
}
|
|
223
|
+
if (partial.settings == undefined || partial.settings.length == 0)
|
|
224
|
+
throw new Error(`Invalid input: missing setting name/value.`);
|
|
225
|
+
// if (partial.setting == undefined || _.isEmpty(partial.setting)) throw new Error(`Invalid input: missing setting name.`)
|
|
226
|
+
if (partial.settings[0].value == undefined || _.isEmpty(partial.settings[0].value))
|
|
227
|
+
throw new Error(`Invalid input: missing setting value.`);
|
|
228
|
+
let output = Object.assign({ enterprise: partial.enterprise, asset: partial.asset, scope: (_a = partial.scope) !== null && _a !== void 0 ? _a : codiac_relay_contracts_1.ScopeLevel.enterprise, target: partial.target, targetFile: (partial.targetFile) ? partial.targetFile : `[${partial.configType}]`, settings: partial.settings,
|
|
229
|
+
// setting: partial.setting,
|
|
230
|
+
// value: partial.value,
|
|
231
|
+
description: partial.description }, this.createAuditable());
|
|
232
|
+
return output;
|
|
233
|
+
}
|
|
234
|
+
catch (err) {
|
|
235
|
+
throw err;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
buildCandidate_interactively(partial, rootMap) {
|
|
239
|
+
var _a;
|
|
240
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
241
|
+
let output;
|
|
178
242
|
try {
|
|
179
|
-
let
|
|
180
|
-
|
|
243
|
+
let partialConfigDef = {};
|
|
244
|
+
partialConfigDef.enterprise = partial.enterprise;
|
|
245
|
+
let enterprise = rootMap.enterprises.find(e => e.name == partial.enterprise);
|
|
246
|
+
if (enterprise == undefined)
|
|
247
|
+
throw new Error("Invalid enterprise"); // <--- here just for TS - shd never get hit (if it hit, itd be guaranteed to confuse the user).
|
|
248
|
+
let confirmed = false;
|
|
249
|
+
do {
|
|
250
|
+
// 1. Select Asset
|
|
251
|
+
let assetChanged;
|
|
252
|
+
[partialConfigDef.asset, assetChanged] = yield this.configUtils.promptForAsset(enterprise.assets, partial.asset);
|
|
253
|
+
// 2. Set Target File
|
|
254
|
+
let selectedFile = (yield this.promptForTargetFile(partial.enterprise, partialConfigDef.asset));
|
|
255
|
+
partialConfigDef.targetFile = selectedFile.targetFile;
|
|
256
|
+
partialConfigDef.settings = selectedFile.settings;
|
|
257
|
+
// 3. Setting
|
|
258
|
+
let settingName;
|
|
259
|
+
let value;
|
|
260
|
+
let instances;
|
|
261
|
+
if (partial.settings != undefined && partial.settings.length > 0) {
|
|
262
|
+
settingName = partial.settings[0].setting;
|
|
263
|
+
value = partial.settings[0].value;
|
|
264
|
+
}
|
|
265
|
+
[settingName, instances] = yield this.configUtils.promptForOneSetting((_a = partialConfigDef.settings) !== null && _a !== void 0 ? _a : [], "write", settingName);
|
|
266
|
+
// 4. Scope
|
|
267
|
+
let selectedScope = yield this.promptForScope(partialConfigDef.enterprise, rootMap, instances);
|
|
268
|
+
partial.scope = selectedScope.scope;
|
|
269
|
+
partial.target = selectedScope.target;
|
|
270
|
+
// 5. Value
|
|
271
|
+
value = yield this.promptForValue({ setting: settingName, value: value, scope: partial.scope, target: partial.target, enterprise: partial.enterprise }, instances, rootMap);
|
|
272
|
+
partial.settings = [{ setting: settingName, value: value }];
|
|
273
|
+
// 6. Confirm or loop back around to enterprise
|
|
274
|
+
confirmed = yield this._ui.promptConfirm("confirm", "Apply? ");
|
|
275
|
+
} while (!confirmed);
|
|
276
|
+
output = Object.assign({
|
|
277
|
+
// setting: partial.setting,
|
|
278
|
+
// value: partial.value,
|
|
279
|
+
settings: partial.settings, targetFile: partialConfigDef.targetFile, asset: partialConfigDef.asset, enterprise: partialConfigDef.enterprise, scope: partial.scope, target: partial.target, description: partial.description }, this.createAuditable());
|
|
181
280
|
return output;
|
|
182
281
|
}
|
|
183
282
|
catch (err) {
|
|
@@ -185,6 +284,50 @@ class ConfigAdd extends command_base_enterprise_1.CommandBaseEnterprise {
|
|
|
185
284
|
}
|
|
186
285
|
});
|
|
187
286
|
}
|
|
287
|
+
buildCommandString(ultimate, cmd) {
|
|
288
|
+
cmd.push("--enterprise", ultimate.enterprise);
|
|
289
|
+
cmd.push("-a", ultimate.asset);
|
|
290
|
+
if (ultimate.configType) {
|
|
291
|
+
cmd.push("-t", ultimate.configType);
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
cmd.push("-f", ultimate.targetFile); // assertion is ok bc we forced one or the other just above ^.
|
|
295
|
+
}
|
|
296
|
+
if (ultimate.scope) {
|
|
297
|
+
if (ultimate.scope == codiac_relay_contracts_1.ScopeLevel.enterprise) {
|
|
298
|
+
cmd.push("--enterprise-scope");
|
|
299
|
+
}
|
|
300
|
+
else if (ultimate.target) {
|
|
301
|
+
if (ultimate.scope == codiac_relay_contracts_1.ScopeLevel.environment)
|
|
302
|
+
cmd.push("-e", ultimate.target);
|
|
303
|
+
if (ultimate.scope == codiac_relay_contracts_1.ScopeLevel.cabinet)
|
|
304
|
+
cmd.push("-c", ultimate.target);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
// NOTE: We can't provide for multiple settings in the cli.
|
|
308
|
+
// Unless:
|
|
309
|
+
// a) we allow multple --setting args and use the --setting "key=value" syntax
|
|
310
|
+
// OR b) we send them back a command string that pipes the settings in
|
|
311
|
+
if (ultimate.settings && ultimate.settings.length > 0) {
|
|
312
|
+
// for (let setting of ultimate.settings) {
|
|
313
|
+
let setting = ultimate.settings[0];
|
|
314
|
+
if (ultimate.settings[0].setting)
|
|
315
|
+
cmd.push("--setting", setting.setting);
|
|
316
|
+
if (ultimate.settings[0].value)
|
|
317
|
+
cmd.push("--value", setting.value);
|
|
318
|
+
// }
|
|
319
|
+
}
|
|
320
|
+
return cmd;
|
|
321
|
+
}
|
|
322
|
+
// private async promptForAsset(assets: AtLeast<Asset, "name">[]): Promise<string> {
|
|
323
|
+
// try {
|
|
324
|
+
// let choices = assets.map(a => { return { name: a.name, value: a.name }; })
|
|
325
|
+
// let output = (await this._ui.promptSelect("asset", "Asset: ", choices))!;
|
|
326
|
+
// return output;
|
|
327
|
+
// } catch (err) {
|
|
328
|
+
// throw err;
|
|
329
|
+
// }
|
|
330
|
+
// }
|
|
188
331
|
promptForValue(setting, existingValues, rootMap) {
|
|
189
332
|
var _a;
|
|
190
333
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -341,52 +484,6 @@ class ConfigAdd extends command_base_enterprise_1.CommandBaseEnterprise {
|
|
|
341
484
|
}
|
|
342
485
|
return output;
|
|
343
486
|
}
|
|
344
|
-
/**
|
|
345
|
-
*
|
|
346
|
-
* Use this inquirer plugin for navigating the object structure:
|
|
347
|
-
* https://github.com/insightfuls/inquirer-tree-prompt
|
|
348
|
-
*
|
|
349
|
-
* See if this file tree selector could be fashioned to do the same:
|
|
350
|
-
* https://github.com/anc95/inquirer-file-tree-selection
|
|
351
|
-
*
|
|
352
|
-
* @param existing
|
|
353
|
-
* @param defaultSetting
|
|
354
|
-
*/
|
|
355
|
-
promptForSetting(existing, defaultSetting) {
|
|
356
|
-
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
357
|
-
try {
|
|
358
|
-
let setting;
|
|
359
|
-
// TODO: render a tree of settings (cant select the branches, just the leaf nodes)
|
|
360
|
-
if (existing.length > 0) {
|
|
361
|
-
// let choices = existing.map(s => { return { name: s.setting, value: s.setting }; });
|
|
362
|
-
let choices = _.uniq(existing.map(s => s.setting));
|
|
363
|
-
choices.push(CodiacConstants.CliConstants.CHOICE_VALUE_FOR_NEW);
|
|
364
|
-
setting = (yield this._ui.promptSelect("settingSelect", "Setting: ", choices));
|
|
365
|
-
}
|
|
366
|
-
if (setting === CodiacConstants.CliConstants.CHOICE_VALUE_FOR_NEW || setting === undefined) {
|
|
367
|
-
setting = (yield this._ui.prompt("settingFreehand", "Setting (use '.' for hierarchy): "));
|
|
368
|
-
}
|
|
369
|
-
if (existing.find(s => s.setting === setting)) {
|
|
370
|
-
// matched an existing setting afterall
|
|
371
|
-
}
|
|
372
|
-
// ----------------------------------------------------------------------------------------------
|
|
373
|
-
// // Try to implement un-selectable options...
|
|
374
|
-
// let settings = ["bill", "sam", "tom", "harry"];
|
|
375
|
-
// let choices: any[] = settings.map(s => { return { name: s, value: s }; });
|
|
376
|
-
// // choices.push({ name: "some branch", value: new inquirer.Separator("--I am a branch") });
|
|
377
|
-
// choices.push(new inquirer.Separator("--I am a branch"));
|
|
378
|
-
// choices.push({ name: "sally", value: "sally" });
|
|
379
|
-
// choices.push({ name: "Sue", value: "Sue" });
|
|
380
|
-
// choices.push({ name: "Suzy", value: "Suzy" });
|
|
381
|
-
// let nada = await this._ui.promptSelect("test", "try this", choices);
|
|
382
|
-
// ----------------------------------------------------------------------------------------------
|
|
383
|
-
return setting;
|
|
384
|
-
}
|
|
385
|
-
catch (err) {
|
|
386
|
-
throw err;
|
|
387
|
-
}
|
|
388
|
-
});
|
|
389
|
-
}
|
|
390
487
|
/** Copy of this method is in config:view */
|
|
391
488
|
promptForTargetFile(enterprise, asset) {
|
|
392
489
|
var _a, _b;
|
|
@@ -460,14 +557,28 @@ class ConfigAdd extends command_base_enterprise_1.CommandBaseEnterprise {
|
|
|
460
557
|
}
|
|
461
558
|
});
|
|
462
559
|
}
|
|
463
|
-
writeSetting_Api(enterprise, assetName, configName, setting, scopeLevel, scopeName, val) {
|
|
560
|
+
// async writeSetting_Api(enterprise: string, assetName: string, configName: string, setting: string, scopeLevel: ScopeLevel, scopeName: string, val: any): Promise<void> {
|
|
561
|
+
// try {
|
|
562
|
+
// let settingObj: ScopedSetting = {
|
|
563
|
+
// setting: setting,
|
|
564
|
+
// value: val,
|
|
565
|
+
// targetFile: configName,
|
|
566
|
+
// asset: assetName,
|
|
567
|
+
// enterprise: enterprise,
|
|
568
|
+
// scope: scopeLevel,
|
|
569
|
+
// target: scopeName,
|
|
570
|
+
// ...this.createAuditable()
|
|
571
|
+
// };
|
|
572
|
+
// return this.upsertSetting(settingObj);
|
|
573
|
+
// } catch (err) {
|
|
574
|
+
// throw err;
|
|
575
|
+
// }
|
|
576
|
+
// }
|
|
577
|
+
executeTask(candidate) {
|
|
464
578
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
}
|
|
469
|
-
catch (err) {
|
|
470
|
-
throw err;
|
|
579
|
+
// TODO: Do this in a single batch call
|
|
580
|
+
for (let setting of candidate.settings) {
|
|
581
|
+
yield this.upsertSetting(Object.assign(Object.assign({}, candidate), { setting: setting.setting, value: setting.value }));
|
|
471
582
|
}
|
|
472
583
|
});
|
|
473
584
|
}
|
|
@@ -475,12 +586,6 @@ class ConfigAdd extends command_base_enterprise_1.CommandBaseEnterprise {
|
|
|
475
586
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
476
587
|
return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
477
588
|
try {
|
|
478
|
-
// TODO: Look to enterprise context instead.
|
|
479
|
-
// let enterprise = /* this._cfg.enterprise || */ this._projCfg.tenantCode;
|
|
480
|
-
// TODO: Look to asset context instead - and if none, fail and call for "$ cod asset:set"
|
|
481
|
-
// let assetName = this._projCfg.name; // this needs to be taken from an image definition. (AssetBinding[] needs to be added to each ImageExport)
|
|
482
|
-
// NOTE: We could bind a config to an image name,
|
|
483
|
-
// and then allow for an Asset scope to set values on it...
|
|
484
589
|
let crit = {
|
|
485
590
|
enterprise: settingObj.enterprise,
|
|
486
591
|
asset: settingObj.asset,
|
|
@@ -547,14 +652,21 @@ ConfigAdd.description = 'Adds a key value pair to the app config';
|
|
|
547
652
|
ConfigAdd.aliases = ['config:set', 'cfg:add'];
|
|
548
653
|
ConfigAdd.flags = {
|
|
549
654
|
help: core_1.Flags.help({ char: 'h' }),
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
655
|
+
enterprise: core_1.Flags.string({ char: 'n', description: '(required only when more than one enterprise exists) The name of the enterprise containing the asset.' }),
|
|
656
|
+
asset: core_1.Flags.string({ char: 'a', description: 'The name of the asset to which the settings belong.' }),
|
|
657
|
+
file: core_1.Flags.string({ char: 'f', description: 'The path-name to the file to which the settings are written, relative to the root of the Codiac project.' }),
|
|
658
|
+
type: core_1.Flags.string({ char: 't', exclusive: ["file"], options: Object.keys(config_ui_utils_1.SpecialConfigTypes), description: 'Filters for the settings types that do not land in a config file (such as... env: OS environment variables, footprint: container footprint specs, and helm: helm chart settings).' }),
|
|
659
|
+
"enterprise-scope": core_1.Flags.boolean({ char: 's', exclusive: ["enviro", "cabinet"], description: 'Filters for settings scoped at the enterprise level.' }),
|
|
660
|
+
enviro: core_1.Flags.string({ char: 'e', exclusive: ["enterprise-scope", "cabinet"], description: 'The name of the environment to which this value is to apply.' }),
|
|
661
|
+
cabinet: core_1.Flags.string({ char: 'c', exclusive: ["enterprise-scope", "enviro"], description: 'The name of the cabinet to which this value is to apply.' }),
|
|
662
|
+
setting: core_1.Flags.string({ required: false, description: "The config key (in dotpath/JSONPath), relative to the root of the config." }),
|
|
663
|
+
value: core_1.Flags.string({ required: false, description: "The actual concrete data to be applied as the setting value." }),
|
|
664
|
+
silent: core_1.Flags.boolean({ exclusive: ["echo", "to-script"], description: 'Non-Interactive mode; executes without any user interaction and fails on any missing or invalid arguments.' }),
|
|
665
|
+
echo: core_1.Flags.boolean({ exclusive: ["to-script", "silent"], description: 'Echo interaction mode; renders the equivalent non-interactive cli command for future use before final execution.' }),
|
|
666
|
+
"to-script": core_1.Flags.boolean({ exclusive: ["echo", "silent"], description: 'Toscript interaction mode; renders the equivalent non-interactive cli command WITHOUT any execution.' }),
|
|
667
|
+
// "take-defaults": Flags.boolean({ exclusive: ["silent"], description: "Prevents prompting for confirmation on parameters that were passed in or were set to default values." }),
|
|
556
668
|
};
|
|
557
669
|
ConfigAdd.args = {
|
|
558
|
-
|
|
670
|
+
// setting: Args.string({ description: 'The key for the config setting to add' })
|
|
559
671
|
};
|
|
560
672
|
//# sourceMappingURL=add.js.map
|