cob-cli 2.46.0-beta.1 → 2.46.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cob-cli.js +9 -0
- package/bin/handleAutoComplete.js +8 -4
- package/lib/commands/getDefs.js +2 -2
- package/lib/commands/init.js +12 -3
- package/lib/commands/package.js +20 -0
- package/lib/commands/test.js +6 -5
- package/lib/commands/updateFromServer.js +113 -13
- package/lib/task_lists/common_enviromentHandler.js +10 -3
- package/lib/task_lists/common_syncFiles.js +4 -0
- package/lib/task_lists/package_execute.js +42 -0
- package/lib/task_lists/test_customUIsContinuosReload.js +38 -7
- package/lib/task_lists/updateFromServer_definitions.js +81 -0
- package/lib/task_lists/updateFromServer_groups.js +68 -0
- package/lib/task_lists/updateFromServer_instances.js +62 -0
- package/lib/task_lists/updateFromServer_kibana.js +57 -0
- package/package.json +8 -4
- package/schema.json +33 -0
- package/.tool-versions +0 -1
- package/tsconfig.json +0 -10
package/bin/cob-cli.js
CHANGED
|
@@ -10,6 +10,7 @@ const init = require("../lib/commands/init");
|
|
|
10
10
|
const customize = require("../lib/commands/customize");
|
|
11
11
|
const test = require("../lib/commands/test");
|
|
12
12
|
const deploy = require("../lib/commands/deploy");
|
|
13
|
+
const package = require("../lib/commands/package");
|
|
13
14
|
const updateFromServer = require("../lib/commands/updateFromServer");
|
|
14
15
|
const getDefs = require("../lib/commands/getDefs");
|
|
15
16
|
const generateMermaid = require("../lib/commands/generateMermaid");
|
|
@@ -73,12 +74,20 @@ program
|
|
|
73
74
|
.description('Deploy customization to the server')
|
|
74
75
|
.action( deploy );
|
|
75
76
|
|
|
77
|
+
program
|
|
78
|
+
.command('package')
|
|
79
|
+
.option('-e --environment <name>', 'environment to use')
|
|
80
|
+
.option('-V --verbose', 'verbose execution of tasks', increaseVerbosity, 0)
|
|
81
|
+
.description('Package customization for out-of-band deploying')
|
|
82
|
+
.action( package );
|
|
83
|
+
|
|
76
84
|
program
|
|
77
85
|
.command('updateFromServer')
|
|
78
86
|
.description('Updates local copy with current files on server, in case of changes made out of standard process.')
|
|
79
87
|
.option('-e --environment <name>', 'environment to use')
|
|
80
88
|
.option('-s --servername <servername>', 'use <servername>.cultofbits.pt (i.e. name without the FQDN)')
|
|
81
89
|
.option('-V --verbose', 'verbose execution of tasks', increaseVerbosity, 0)
|
|
90
|
+
.option('-c --code', 'By adding this flag you indicate that you want to bring the code and not the data')
|
|
82
91
|
.action( updateFromServer );
|
|
83
92
|
|
|
84
93
|
program
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
2
|
|
|
3
|
-
if(process.platform === 'win32'){
|
|
4
|
-
return;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
3
|
/* Autocomplete Component*/
|
|
8
4
|
var omelette = require('omelette');
|
|
9
5
|
const commandStructure = {
|
|
@@ -19,11 +15,19 @@ completion.init()
|
|
|
19
15
|
|
|
20
16
|
// add to system profiles
|
|
21
17
|
if (~process.argv.indexOf('--setup')) {
|
|
18
|
+
if (process.platform === 'win32') {
|
|
19
|
+
// we exit cleanly so that postinstall completes successfuly
|
|
20
|
+
process.exit(0)
|
|
21
|
+
}
|
|
22
22
|
console.log("Setting up...")
|
|
23
23
|
completion.setupShellInitFile()
|
|
24
24
|
}
|
|
25
25
|
// remove from system profiles
|
|
26
26
|
if (~process.argv.indexOf('--cleanup')) {
|
|
27
|
+
if (process.platform === 'win32') {
|
|
28
|
+
// we exit cleanly so that uninstall completes successfuly
|
|
29
|
+
process.exit(0)
|
|
30
|
+
}
|
|
27
31
|
console.log("Cleaning...")
|
|
28
32
|
completion.cleanupShellInitFile()
|
|
29
33
|
}
|
package/lib/commands/getDefs.js
CHANGED
|
@@ -10,11 +10,11 @@ async function getDefs(args) {
|
|
|
10
10
|
const cmdEnv = await getCurrentCommandEnviroment(args)
|
|
11
11
|
|
|
12
12
|
console.log(`Getting definitions from ${cmdEnv.serverStr} to branch ${cmdEnv.branchStr} ...` );
|
|
13
|
-
const getDefs = spawn(path.resolve(__dirname,"..","task_lists","getDefs.sh"),[cmdEnv.
|
|
13
|
+
const getDefs = spawn(path.resolve(__dirname,"..","task_lists","getDefs.sh"),[cmdEnv.serverHTTPs, cmdEnv.name, path.resolve(__dirname) ])
|
|
14
14
|
getDefs.stdout.on('data', function (data) { console.log(" " + data.toString()); });
|
|
15
15
|
getDefs.on('exit', function () { console.log('Done!'); });
|
|
16
16
|
} catch(err) {
|
|
17
17
|
console.error("\n",err.message);
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
module.exports = getDefs;
|
|
20
|
+
module.exports = getDefs;
|
package/lib/commands/init.js
CHANGED
|
@@ -16,7 +16,7 @@ async function init(servername,args) {
|
|
|
16
16
|
let initTasks;
|
|
17
17
|
if(await projectExistsInGitAccount(projectName,args.repoaccount) ) {
|
|
18
18
|
console.log("\nRepo cloned!".green);
|
|
19
|
-
} else if( projectPathOkFor(projectName) && await notInsideGitRepo() && await validCobServer(cmdEnv.
|
|
19
|
+
} else if( projectPathOkFor(projectName) && await notInsideGitRepo() && await validCobServer(cmdEnv.serverHTTPs)) {
|
|
20
20
|
console.log("\nCreating project", projectName.bold.blue );
|
|
21
21
|
initTasks = newProjectTasks(cmdEnv, projectName, repo, args )
|
|
22
22
|
initTasks.run()
|
|
@@ -71,9 +71,18 @@ async function validCobServer(server) {
|
|
|
71
71
|
/* ************************************ */
|
|
72
72
|
async function projectExistsInGitAccount(projectName, repoaccount) {
|
|
73
73
|
try {
|
|
74
|
-
|
|
74
|
+
let cloneConfs = []
|
|
75
|
+
if(process.platform === 'win32'){
|
|
76
|
+
// on windows we force the usage of lf as line-endings
|
|
77
|
+
// so that rsync doesn't think all files have changed
|
|
78
|
+
cloneConfs = [
|
|
79
|
+
'--config', 'core.autocrlf=input',
|
|
80
|
+
'--config', 'core.eol=lf'
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
await git().clone(repoaccount + projectName, cloneConfs);
|
|
75
84
|
return true;
|
|
76
85
|
} catch (e) {
|
|
77
86
|
return false
|
|
78
87
|
}
|
|
79
|
-
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require('colors');
|
|
2
|
+
const { checkRepoVersion } = require("../commands/upgradeRepo");
|
|
3
|
+
const { getCurrentCommandEnviroment } = require("../task_lists/common_enviromentHandler");
|
|
4
|
+
const { executeTasks } = require("../task_lists/package_execute");
|
|
5
|
+
|
|
6
|
+
async function package(args) {
|
|
7
|
+
try {
|
|
8
|
+
checkRepoVersion()
|
|
9
|
+
const cmdEnv = await getCurrentCommandEnviroment(args)
|
|
10
|
+
if(args.resync) args.force = true;
|
|
11
|
+
|
|
12
|
+
await executeTasks(cmdEnv, args).run();
|
|
13
|
+
|
|
14
|
+
console.log("\nDone!".green, "\nEnjoy!")
|
|
15
|
+
|
|
16
|
+
} catch(err) {
|
|
17
|
+
console.error("\n",err.message);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
module.exports = package;
|
package/lib/commands/test.js
CHANGED
|
@@ -10,6 +10,7 @@ const { checkRepoVersion } = require("../commands/upgradeRepo");
|
|
|
10
10
|
async function test (args) {
|
|
11
11
|
let restoreChanges, error = "";
|
|
12
12
|
let cmdEnv
|
|
13
|
+
let spawned
|
|
13
14
|
try {
|
|
14
15
|
checkRepoVersion()
|
|
15
16
|
console.log("Start testing… ")
|
|
@@ -22,8 +23,8 @@ async function test (args) {
|
|
|
22
23
|
} else {
|
|
23
24
|
await cmdEnv.applyCurrentCommandEnvironmentChanges()
|
|
24
25
|
}
|
|
25
|
-
customUIsContinuosReload(cmdEnv, args.dashboard)
|
|
26
|
-
|
|
26
|
+
spawned = await customUIsContinuosReload(cmdEnv, args.dashboard)
|
|
27
|
+
|
|
27
28
|
let key;
|
|
28
29
|
do {
|
|
29
30
|
key = await getKeypress()
|
|
@@ -36,8 +37,8 @@ async function test (args) {
|
|
|
36
37
|
} finally {
|
|
37
38
|
restoreChanges && await restoreChanges()
|
|
38
39
|
cmdEnv && await cmdEnv.unApplyCurrentCommandEnvironmentChanges() // Repõe as configurações
|
|
39
|
-
|
|
40
|
-
// Dá tempo aos subprocessos para morrer
|
|
40
|
+
spawned && await spawned.stop();
|
|
41
|
+
// Dá tempo aos subprocessos para morrer (acho que já não é preciso)
|
|
41
42
|
setTimeout(() => {
|
|
42
43
|
if(!error) {
|
|
43
44
|
console.log( "\n"
|
|
@@ -49,4 +50,4 @@ async function test (args) {
|
|
|
49
50
|
}, 2000);
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
|
-
module.exports = test
|
|
53
|
+
module.exports = test
|
|
@@ -2,30 +2,130 @@ require('colors');
|
|
|
2
2
|
const { getCurrentCommandEnviroment } = require("../task_lists/common_enviromentHandler");
|
|
3
3
|
const { copyFiles } = require("../task_lists/common_syncFiles");
|
|
4
4
|
const { validateUpdateFromServerConditions } = require("../task_lists/updateFromServer_validate");
|
|
5
|
+
const { getGroupsFromServer } = require("../task_lists/updateFromServer_groups");
|
|
6
|
+
const { getDefinitionsFromServer } = require("../task_lists/updateFromServer_definitions");
|
|
7
|
+
const { getInstancesFromServer } = require("../task_lists/updateFromServer_instances");
|
|
8
|
+
const { getKibanaFromServer } = require("../task_lists/updateFromServer_kibana");
|
|
5
9
|
const { checkRepoVersion } = require("../commands/upgradeRepo");
|
|
10
|
+
const inquirer = require("inquirer")
|
|
11
|
+
const axios = require('axios');
|
|
12
|
+
const tough = require('tough-cookie');
|
|
13
|
+
const fs = require("fs/promises");
|
|
14
|
+
const yaml = require('js-yaml');
|
|
15
|
+
const axiosCookieJarSupport = require('axios-cookiejar-support')
|
|
6
16
|
|
|
7
17
|
async function updateFromServer(args) {
|
|
8
18
|
try {
|
|
9
19
|
checkRepoVersion()
|
|
10
20
|
const cmdEnv = await getCurrentCommandEnviroment(args)
|
|
11
21
|
|
|
12
|
-
|
|
22
|
+
if (args.code) {
|
|
13
23
|
|
|
14
|
-
|
|
15
|
-
await cmdEnv.applyCurrentCommandEnvironmentChanges()
|
|
16
|
-
let changes = await copyFiles(cmdEnv, "serverLive", "localCopy", args)
|
|
17
|
-
await cmdEnv.unApplyCurrentCommandEnvironmentChanges()
|
|
24
|
+
await validateUpdateFromServerConditions(cmdEnv).run()
|
|
18
25
|
|
|
19
|
-
|
|
20
|
-
|
|
26
|
+
console.log("\nOk to proceed. Getting files from server's live directories...");
|
|
27
|
+
await cmdEnv.applyCurrentCommandEnvironmentChanges()
|
|
28
|
+
let changes = await copyFiles(cmdEnv, "serverLive", "localCopy", args)
|
|
29
|
+
await cmdEnv.unApplyCurrentCommandEnvironmentChanges()
|
|
30
|
+
|
|
31
|
+
if (changes.length == 0) {
|
|
32
|
+
console.log("\nFinished.".green, "Nothing todo, no changes detected.");
|
|
33
|
+
} else {
|
|
34
|
+
console.log("\n " + changes.join("\n "));
|
|
35
|
+
console.log("\nUpdate done!".yellow, "Check", "git status".bold.blue, "and", "git diff".bold.blue, "to see the resulting differences.");
|
|
36
|
+
console.log("Notice that", "any changes since last deploy migth be lost.".underline)
|
|
37
|
+
console.log("Notice also that you will need to do a", "cob-cli deploy --force".bold.blue, "on next deploy.")
|
|
38
|
+
}
|
|
21
39
|
} else {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
40
|
+
|
|
41
|
+
const cookieJar = new tough.CookieJar()
|
|
42
|
+
axiosCookieJarSupport.wrapper(axios)
|
|
43
|
+
axios.defaults.jar = cookieJar
|
|
44
|
+
axios.defaults.ignoreCookieErrors = true
|
|
45
|
+
axios.defaults.withCredentials = true
|
|
46
|
+
|
|
47
|
+
const credentials = await getCredentials()
|
|
48
|
+
|
|
49
|
+
await axios.post(`https://${cmdEnv.servername}.cultofbits.com/recordm/security/auth`, credentials, {
|
|
50
|
+
headers: {
|
|
51
|
+
"Content-Type": "application/json",
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const customizations = await readConfig()
|
|
56
|
+
|
|
57
|
+
for (const customization of customizations) {
|
|
58
|
+
|
|
59
|
+
console.log("\nStarting updateFromServer of customization " + customization.name)
|
|
60
|
+
|
|
61
|
+
const dataPath = 'others/customizationData/' + customization.name
|
|
62
|
+
fs.mkdir(dataPath, { recursive: true })
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
if (customization.permissions) {
|
|
66
|
+
await getGroupsFromServer(cmdEnv.servername, customization.permissions.query, dataPath + "/permissions.json", customization.name)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (customization.definitions) {
|
|
70
|
+
const definitionPath = dataPath + '/definitions/'
|
|
71
|
+
fs.mkdir(definitionPath, { recursive: true })
|
|
72
|
+
const viewsPath = dataPath + '/views/'
|
|
73
|
+
fs.mkdir(viewsPath, { recursive: true })
|
|
74
|
+
await getDefinitionsFromServer(cmdEnv.servername, customization.definitions.filter, definitionPath, viewsPath, customization.name)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (customization.instances) {
|
|
78
|
+
const instancesPath = dataPath + '/instances/'
|
|
79
|
+
fs.mkdir(instancesPath, { recursive: true })
|
|
80
|
+
await getInstancesFromServer(cmdEnv.servername, customization.instances, instancesPath, customization.name)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if(customization.kibana){
|
|
84
|
+
const kibanaPath = dataPath + '/kibana/'
|
|
85
|
+
fs.mkdir(kibanaPath, { recursive: true })
|
|
86
|
+
await getKibanaFromServer(cmdEnv.servername, customization.kibana.spaces, kibanaPath, customization.name)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
}
|
|
26
90
|
}
|
|
27
|
-
|
|
28
|
-
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
} catch (err) {
|
|
94
|
+
console.error("\n", err.message);
|
|
29
95
|
}
|
|
30
96
|
}
|
|
97
|
+
|
|
98
|
+
async function readConfig() {
|
|
99
|
+
try {
|
|
100
|
+
const data = await fs.readFile("customizationsDef.yml", 'utf-8');
|
|
101
|
+
const config = yaml.load(data);
|
|
102
|
+
return config
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error('Error reading YAML file:', error.message);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
const getCredentials = async () => {
|
|
110
|
+
|
|
111
|
+
const answers = await inquirer
|
|
112
|
+
.prompt([
|
|
113
|
+
{
|
|
114
|
+
type: 'text',
|
|
115
|
+
message: 'Enter username:',
|
|
116
|
+
name: 'username',
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
type: 'password',
|
|
120
|
+
message: 'Enter password:',
|
|
121
|
+
name: 'password',
|
|
122
|
+
mask: '*',
|
|
123
|
+
},
|
|
124
|
+
])
|
|
125
|
+
|
|
126
|
+
return answers
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
31
131
|
module.exports = updateFromServer;
|
|
@@ -15,7 +15,8 @@ async function getCurrentCommandEnviroment(args, newServername) {
|
|
|
15
15
|
|
|
16
16
|
const defaultEnvironmentServerName = newServername ? newServername : _getDefaultServerForEnvironment(environmentName);
|
|
17
17
|
const servername = args.servername ? args.servername : defaultEnvironmentServerName;
|
|
18
|
-
const server =
|
|
18
|
+
const server = _getServerSSHFQDN(servername)
|
|
19
|
+
const serverHTTPs = _getServerHTTPsFQDN(servername)
|
|
19
20
|
const currentBranch = newServername ? "master" : await getCurrentBranch();
|
|
20
21
|
|
|
21
22
|
const lastEnvironmentDeployedToServer = await _getLastEnvironmentDeployed(server)
|
|
@@ -47,6 +48,7 @@ async function getCurrentCommandEnviroment(args, newServername) {
|
|
|
47
48
|
name: environmentName,
|
|
48
49
|
servername: servername,
|
|
49
50
|
server: server,
|
|
51
|
+
serverHTTPs: serverHTTPs,
|
|
50
52
|
serverStr: serverStr,
|
|
51
53
|
currentBranch: currentBranch,
|
|
52
54
|
branchStr: branchStr,
|
|
@@ -117,10 +119,15 @@ function _getDefaultServerForEnvironment(environmentName) {
|
|
|
117
119
|
}
|
|
118
120
|
|
|
119
121
|
/* ************************************ */
|
|
120
|
-
function
|
|
122
|
+
function _getServerSSHFQDN(servername) {
|
|
121
123
|
return servername + ".cultofbits.pt";
|
|
122
124
|
}
|
|
123
125
|
|
|
126
|
+
/* ************************************ */
|
|
127
|
+
function _getServerHTTPsFQDN(servername) {
|
|
128
|
+
return servername + ".cultofbits.com";
|
|
129
|
+
}
|
|
130
|
+
|
|
124
131
|
/* ************************************ */
|
|
125
132
|
async function _getLastEnvironmentDeployed(server) {
|
|
126
133
|
try {
|
|
@@ -140,4 +147,4 @@ async function _setLastEnvironmentDeployed(server, environmentName) {
|
|
|
140
147
|
async function _setupEnvironment(environmentName, servername, server) {
|
|
141
148
|
await fs.mkdirs("environments/" + environmentName);
|
|
142
149
|
await fs.writeFile("environments/" + environmentName + "/server", servername);
|
|
143
|
-
}
|
|
150
|
+
}
|
|
@@ -32,6 +32,7 @@ async function _syncFiles(executionType, cmdEnv, from, to, extraOptions = [], ar
|
|
|
32
32
|
return new Promise(async (resolve, reject) => {
|
|
33
33
|
let fromPath = resolveCobPath(cmdEnv.server, from, product);
|
|
34
34
|
let toPath = resolveCobPath(cmdEnv.server, to, product);
|
|
35
|
+
if (toPath.startsWith('.') && !fs.existsSync(toPath)) fs.mkdirSync(toPath)
|
|
35
36
|
let productExtraOptions = extraOptions.map( option => option.replace(/=.*\|/,"="))
|
|
36
37
|
productExtraOptions = productExtraOptions.filter( option => option.indexOf("|") < 0 )
|
|
37
38
|
|
|
@@ -178,6 +179,9 @@ function resolveCobPath(server, type, product) {
|
|
|
178
179
|
default:
|
|
179
180
|
return server + ':' + "/etc/" + product + "/";
|
|
180
181
|
}
|
|
182
|
+
|
|
183
|
+
case "staging":
|
|
184
|
+
return ".staging/" + product + "/";
|
|
181
185
|
}
|
|
182
186
|
}
|
|
183
187
|
exports.resolveCobPath = resolveCobPath;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const Listr = require('listr');
|
|
2
|
+
const UpdaterRenderer = require('listr-update-renderer');
|
|
3
|
+
const verboseRenderer = require('listr-verbose-renderer');
|
|
4
|
+
const { copyFiles } = require("./common_syncFiles");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const tar = require('tar');
|
|
7
|
+
const { format } = require('date-fns');
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
function executeTasks(cmdEnv, args) {
|
|
11
|
+
console.log("\nPackaging ...");
|
|
12
|
+
|
|
13
|
+
return new Listr([
|
|
14
|
+
{title: "Apply new enviroment specifics", task: () => cmdEnv.applyCurrentCommandEnvironmentChanges() },
|
|
15
|
+
{title: "Create staging dir", task: () => fs.existsSync('.staging') || fs.mkdirSync('.staging') },
|
|
16
|
+
{title: "Copy files to staging dir", task: () => copyFiles(cmdEnv, "localCopy", "staging")},
|
|
17
|
+
{title: "Create package", task: async () => { const filename = await createPackage(cmdEnv, args); console.log("created " + filename) }},
|
|
18
|
+
{title: "Sign package", task: () => console.log("lololo")},
|
|
19
|
+
{title: "Delete staging dir", task: () => fs.rmSync('.staging', {recursive: true, force: true})},
|
|
20
|
+
{title: "Undo new enviroment specifics", task: () => cmdEnv.unApplyCurrentCommandEnvironmentChanges() },
|
|
21
|
+
], {
|
|
22
|
+
renderer: args.verbose ? verboseRenderer : UpdaterRenderer,
|
|
23
|
+
collapse: false
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
exports.executeTasks = executeTasks;
|
|
27
|
+
|
|
28
|
+
const createPackage = async function(cmdEnv, args){
|
|
29
|
+
const filename = `${cmdEnv.servername}-${cmdEnv.name}-${format(new Date(), 'yyyy-MM-dd_HH:mm')}.tar.gz`;
|
|
30
|
+
const files = fs.readdirSync('.staging')
|
|
31
|
+
if (args.verbose > 0){
|
|
32
|
+
console.log("packaging " + files)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
await tar.create({
|
|
36
|
+
gzip: true,
|
|
37
|
+
file: filename,
|
|
38
|
+
cwd: '.staging'
|
|
39
|
+
}, files)
|
|
40
|
+
|
|
41
|
+
return filename;
|
|
42
|
+
}
|
|
@@ -2,12 +2,17 @@ const execa = require('execa');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const concurrently = require('concurrently');
|
|
4
4
|
const fs= require('fs');
|
|
5
|
+
const util = require('util');
|
|
6
|
+
const child_process = require('child_process');
|
|
7
|
+
const exec = util.promisify(child_process.exec);
|
|
8
|
+
|
|
5
9
|
|
|
6
10
|
async function customUIsContinuosReload(cmdEnv, dashboard) {
|
|
7
11
|
process.env.dash_dir = dashboard
|
|
8
|
-
process.env.server = "https://" + cmdEnv.
|
|
12
|
+
process.env.server = "https://" + cmdEnv.serverHTTPs
|
|
9
13
|
|
|
10
14
|
let commands = []
|
|
15
|
+
let isStopping = false;
|
|
11
16
|
|
|
12
17
|
let dashboardPath = path.resolve(".") + "/recordm/customUI/" + dashboard;
|
|
13
18
|
let dashboardPathIsDirectory = false;
|
|
@@ -47,14 +52,40 @@ async function customUIsContinuosReload(cmdEnv, dashboard) {
|
|
|
47
52
|
prefixColor: "blue"
|
|
48
53
|
})
|
|
49
54
|
|
|
50
|
-
concurrently( commands, {
|
|
55
|
+
const conc = concurrently( commands, {
|
|
51
56
|
prefix: 'name',
|
|
52
57
|
inputStream: process.stdin,
|
|
53
58
|
handleInput: false,
|
|
54
59
|
killOthers: ['failure', 'success']
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const stopEverything = async function(){
|
|
63
|
+
isStopping = true;
|
|
64
|
+
for(const spawn of conc.commands) {
|
|
65
|
+
// console.log("\n killing spawn [" + spawn.pid + "] " + spawn.command )
|
|
66
|
+
|
|
67
|
+
// win32 seems to not kill child processes, and concurrently wraps executions with a cmd.exe shell
|
|
68
|
+
if (process.platform === 'win32') {
|
|
69
|
+
try {
|
|
70
|
+
await exec(`taskkill /PID ${spawn.pid} /T /F`)
|
|
71
|
+
} catch (err) {
|
|
72
|
+
console.error("error trying to taskkill process tree", err)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
} else {
|
|
76
|
+
spawn.kill("SIGINT");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
conc.result.catch( _err => {
|
|
82
|
+
if(isStopping) return;
|
|
83
|
+
|
|
84
|
+
stopEverything();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
stop: stopEverything
|
|
89
|
+
};
|
|
59
90
|
}
|
|
60
|
-
exports.customUIsContinuosReload = customUIsContinuosReload;
|
|
91
|
+
exports.customUIsContinuosReload = customUIsContinuosReload;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require('colors');
|
|
2
|
+
const Listr = require('listr');
|
|
3
|
+
const UpdaterRenderer = require('listr-update-renderer');
|
|
4
|
+
const axios = require("axios");
|
|
5
|
+
const fs = require("fs/promises");
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async function getDefinitions(servername, queries) {
|
|
9
|
+
|
|
10
|
+
const uri = `https://${servername}.cultofbits.com/recordm/recordm/definitions`
|
|
11
|
+
const response = await axios.get( uri );
|
|
12
|
+
|
|
13
|
+
if(response.status != 200){
|
|
14
|
+
throw new Error(`HTTP Error Response: ${response.status} ${response.statusText}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const matchesAny = (def) => queries.filter(q => match(q, def)).length > 0;
|
|
18
|
+
|
|
19
|
+
return response.data
|
|
20
|
+
.filter( matchesAny )
|
|
21
|
+
.map( def => ({id: def.id, name: def.name}) )
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function match(query, definition) {
|
|
25
|
+
// simple matching for now
|
|
26
|
+
return definition.name.includes(query) || definition.description.includes(query)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function exportDefinitionChanges(servername, id, dataPath) {
|
|
30
|
+
|
|
31
|
+
const uri = `https://${servername}.cultofbits.com/recordm/recordm/definitions/${id}/changes`
|
|
32
|
+
const response = await axios.get(uri);
|
|
33
|
+
|
|
34
|
+
if(response.status != 200){
|
|
35
|
+
throw new Error(`HTTP Error Response: ${response.status} ${response.statusText}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const jsonLines = response.data.map(change => JSON.stringify(change)).join('\n');
|
|
39
|
+
|
|
40
|
+
await fs.writeFile(dataPath, jsonLines, 'utf-8');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function getViewsForDef(servername, definition, dataPath, user) {
|
|
44
|
+
const definitionId = definition.id
|
|
45
|
+
const uri = `https://${servername}.cultofbits.com/recordm/user/settings/definitions-${definitionId}/views?`
|
|
46
|
+
|
|
47
|
+
const response = await axios.get(uri);
|
|
48
|
+
|
|
49
|
+
if(response.status != 200){
|
|
50
|
+
throw new Error(`HTTP Error Response: ${response.status} ${response.statusText}`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const userViews = response.data.filter(v => v.user == user)
|
|
54
|
+
|
|
55
|
+
if(userViews.length == 0)
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
const jsonLines = userViews.map(change => JSON.stringify(change))
|
|
59
|
+
.join('\n');
|
|
60
|
+
|
|
61
|
+
await fs.writeFile(dataPath, jsonLines)
|
|
62
|
+
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function getDefinitionsFromServer(servername, queries, definitionsPath, viewsPath, customization, user) {
|
|
66
|
+
|
|
67
|
+
await new Listr(
|
|
68
|
+
[
|
|
69
|
+
{ title: `(${customization}) Definitions: `.bold + "searching for definitions matching queries", task: async ctx => ctx.defs = await getDefinitions(servername, queries) },
|
|
70
|
+
{ title: `(${customization}) Definitions: `.bold + "exporting changes for definitions", task: ctx => ctx.defs.forEach( d => exportDefinitionChanges(servername, d.id, definitionsPath + `${d.name}.jsonl`) ) },
|
|
71
|
+
{ title: `(${customization}) Definitions: `.bold + "exporting views for definitions", task: ctx => ctx.defs.forEach( d => getViewsForDef(servername, d, viewsPath + `${d.name}.jsonl`, user) ) },
|
|
72
|
+
],{
|
|
73
|
+
renderer: UpdaterRenderer,
|
|
74
|
+
collapse: false
|
|
75
|
+
})
|
|
76
|
+
.run()
|
|
77
|
+
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
exports.getDefinitionsFromServer = getDefinitionsFromServer
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require('colors');
|
|
2
|
+
const Listr = require('listr');
|
|
3
|
+
const UpdaterRenderer = require('listr-update-renderer');
|
|
4
|
+
const axios = require("axios");
|
|
5
|
+
const fs = require("fs/promises");
|
|
6
|
+
|
|
7
|
+
async function getGroups(query, servername) {
|
|
8
|
+
|
|
9
|
+
const uri = `https://${servername}.cultofbits.com/userm/userm/search/userm/group?`
|
|
10
|
+
const response = await axios.get( uri + new URLSearchParams({
|
|
11
|
+
q: query,
|
|
12
|
+
size: "100" // probably excessive
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
if(response.status != 200){
|
|
16
|
+
throw new Error(`HTTP Error Response: ${response.status} ${response.statusText}`);
|
|
17
|
+
}
|
|
18
|
+
const groupIds = response.data.hits.hits.map((h) => h._id)
|
|
19
|
+
return groupIds;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const sortByName = (a, b) => a.name?.localeCompare(b.name);
|
|
23
|
+
|
|
24
|
+
const exportGroups = async function(ids, servername, exportPath){
|
|
25
|
+
|
|
26
|
+
const uri = `https://${servername}.cultofbits.com/userm/userm/group/export/${ids.join(',')}`
|
|
27
|
+
|
|
28
|
+
const response = await axios.get( uri );
|
|
29
|
+
if(response.status != 200 ){
|
|
30
|
+
throw new Error(`HTTP Error Response: ${response.status} ${response.statusText}`);
|
|
31
|
+
}
|
|
32
|
+
const data = response.data;
|
|
33
|
+
|
|
34
|
+
// sort everything to be easier to diff
|
|
35
|
+
data.groups?.sort(sortByName);
|
|
36
|
+
data.groups?.forEach(group => group.roles?.sort())
|
|
37
|
+
data.roles?.sort(sortByName);
|
|
38
|
+
data.roles?.forEach(role => role.perms?.sort())
|
|
39
|
+
data.perms?.sort(sortByName);
|
|
40
|
+
|
|
41
|
+
fs.writeFile(exportPath, JSON.stringify(data, null, 2))
|
|
42
|
+
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
async function groupsFromServer(servername, groupsQueries, exportPath, customization) {
|
|
46
|
+
const searchTasks = groupsQueries.map( gp =>
|
|
47
|
+
({ title: `(${customization}) Permissions: `.bold + "searching for groups with query: " + gp,
|
|
48
|
+
task: async ctx => ctx.groupIds = ctx.groupIds
|
|
49
|
+
? ctx.groupIds.concat(await getGroups(gp, servername))
|
|
50
|
+
: await getGroups(gp, servername) }))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
await new Listr(
|
|
55
|
+
[
|
|
56
|
+
...searchTasks,
|
|
57
|
+
{ title: `(${customization}) Permissions: `.bold + "exporting groups and subsequent roles/permissions", task: ctx => exportGroups(ctx.groupIds, servername, exportPath)},
|
|
58
|
+
],{
|
|
59
|
+
renderer: UpdaterRenderer,
|
|
60
|
+
collapse: false
|
|
61
|
+
})
|
|
62
|
+
.run()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
exports.getGroupsFromServer = groupsFromServer
|
|
67
|
+
|
|
68
|
+
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require('colors');
|
|
2
|
+
const Listr = require('listr');
|
|
3
|
+
const UpdaterRenderer = require('listr-update-renderer');
|
|
4
|
+
const axios = require("axios");
|
|
5
|
+
const fs = require("fs/promises");
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async function getInstancesFromServer(servername, definitionsForInstances, rootPath, customization) {
|
|
9
|
+
|
|
10
|
+
const taskList = definitionsForInstances.map( def => ({
|
|
11
|
+
title: `(${customization}) Instances: `.bold + `Exporting instances from definition ${def.definition}`,
|
|
12
|
+
task: async ctx => getInstancesOfDefinition(servername, await getDefinition(servername, def.definition), def.query, rootPath)
|
|
13
|
+
}))
|
|
14
|
+
|
|
15
|
+
await new Listr(taskList , {
|
|
16
|
+
renderer: UpdaterRenderer,
|
|
17
|
+
collapse: false
|
|
18
|
+
}).run()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getFieldList(definition) {
|
|
25
|
+
return Array.from(
|
|
26
|
+
new Set(flattenFields(definition.fieldDefinitions))
|
|
27
|
+
).join(',')
|
|
28
|
+
}
|
|
29
|
+
function flattenFields(fieldArray) {
|
|
30
|
+
if (!fieldArray || fieldArray.length == 0)
|
|
31
|
+
return []
|
|
32
|
+
|
|
33
|
+
return fieldArray.flatMap(field => flattenFields(field.fields).concat([field.name]))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
async function getInstancesOfDefinition(servername, definition, query, rootPath) {
|
|
38
|
+
|
|
39
|
+
const definitionId = definition.id
|
|
40
|
+
|
|
41
|
+
const uri = `https://${servername}.cultofbits.com/recordm/recordm/definitions/search/download/${definitionId}?`
|
|
42
|
+
const response = await axios.get(uri + new URLSearchParams({
|
|
43
|
+
q: query,
|
|
44
|
+
vcn: getFieldList(definition)
|
|
45
|
+
}), {
|
|
46
|
+
responseType: 'arraybuffer',
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
fs.writeFile(rootPath + `${definition.name}.xlsx`, response.data)
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function getDefinition(servername, definitionName) {
|
|
54
|
+
|
|
55
|
+
const uri = `https://${servername}.cultofbits.com/recordm/recordm/definitions/name/${definitionName}`
|
|
56
|
+
const response = await axios.get(uri);
|
|
57
|
+
|
|
58
|
+
return response.data
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
exports.getInstancesFromServer = getInstancesFromServer
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require('colors');
|
|
2
|
+
const Listr = require('listr');
|
|
3
|
+
const UpdaterRenderer = require('listr-update-renderer');
|
|
4
|
+
const axios = require("axios");
|
|
5
|
+
const fs = require("fs/promises");
|
|
6
|
+
|
|
7
|
+
async function exportSavedObjectsOfSpace(servername, space, filePath) {
|
|
8
|
+
|
|
9
|
+
const uri = `https://${servername}.cultofbits.com/kibana/s/${space.toLowerCase()}/api/kibana/management/saved_objects/_find?perPage=1000&type=config&type=url&type=index-pattern&type=query&type=tag&type=canvas-element&type=canvas-workpad&type=action&type=alert&type=visualization&type=dashboard&type=map&type=lens&type=cases&type=search&sortField=type`
|
|
10
|
+
const response = await axios.get( uri );
|
|
11
|
+
|
|
12
|
+
if(response.status != 200){
|
|
13
|
+
throw new Error(`HTTP Error Response: ${response.status} ${response.statusText}`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
await Promise.all(response.data.saved_objects.map(async element => { if(element.type === "index-pattern") await replaceIndexPatternsIds(servername, element) }))
|
|
17
|
+
|
|
18
|
+
fs.writeFile(filePath, JSON.stringify(response.data.saved_objects, null, 2))
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// replaces in place
|
|
22
|
+
async function replaceIndexPatternsIds(servername, indexPattern) {
|
|
23
|
+
if(indexPattern.type !== "index-pattern"){
|
|
24
|
+
throw new Error("Not an index pattern")
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const definitionId = indexPattern.meta.title.substring('recordm-'.length)
|
|
28
|
+
const name = await getDefinitionName(servername, definitionId)
|
|
29
|
+
|
|
30
|
+
indexPattern.meta.title = `recordm-§§${name}§§`
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function getDefinitionName(servername, id) {
|
|
34
|
+
const uri = `https://${servername}.cultofbits.com/recordm/recordm/definitions/${id}`
|
|
35
|
+
const response = await axios.get( uri );
|
|
36
|
+
|
|
37
|
+
if(response.status != 200){
|
|
38
|
+
throw new Error(`HTTP Error Response: ${response.status} ${response.statusText}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return response.data.name
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function getKibanaFromServer(servername, spaces, roothpath, customization) {
|
|
45
|
+
|
|
46
|
+
const taskList = spaces.map( space => (
|
|
47
|
+
{ title: `(${customization}) Kibana: `.bold + `Exporting ${space}`, task: async ctx => ctx.groupIds = await exportSavedObjectsOfSpace(servername, space, roothpath + `/${space}.json`) }
|
|
48
|
+
))
|
|
49
|
+
|
|
50
|
+
await new Listr( taskList, {
|
|
51
|
+
renderer: UpdaterRenderer,
|
|
52
|
+
collapse: false
|
|
53
|
+
})
|
|
54
|
+
.run()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
exports.getKibanaFromServer = getKibanaFromServer
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cob-cli",
|
|
3
|
-
"version": "2.46.0-beta.
|
|
3
|
+
"version": "2.46.0-beta.11",
|
|
4
4
|
"description": "A command line utility to help Cult of Bits partners develop with higher speed and reusing common code and best practices.",
|
|
5
5
|
"preferGlobal": true,
|
|
6
6
|
"repository": {
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
},
|
|
10
10
|
"main": "./bin/cob-cli.js",
|
|
11
11
|
"scripts": {
|
|
12
|
-
"postinstall": "bin/cob-cli.js --setup",
|
|
13
|
-
"uninstall": "bin/cob-cli.js --cleanup"
|
|
12
|
+
"postinstall": "node bin/cob-cli.js --setup",
|
|
13
|
+
"uninstall": "node bin/cob-cli.js --cleanup"
|
|
14
14
|
},
|
|
15
15
|
"bin": {
|
|
16
16
|
"cob-cli": "bin/cob-cli.js"
|
|
@@ -18,21 +18,25 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@webpack-cli/serve": "^2.0.1",
|
|
20
20
|
"axios": "^0.21.1",
|
|
21
|
+
"axios-cookiejar-support": "^5.0.5",
|
|
21
22
|
"chokidar": "^3.5.3",
|
|
22
23
|
"cmd-line-importer": "^1.0.0",
|
|
23
24
|
"colors": "^1.4.0",
|
|
24
25
|
"commander": "^5.1.0",
|
|
25
|
-
"concurrently": "^
|
|
26
|
+
"concurrently": "^8.0.0",
|
|
26
27
|
"execa": "^4.0.3",
|
|
27
28
|
"fast-glob": "^3.2.5",
|
|
28
29
|
"file-cookie-store": "^0.2.1",
|
|
29
30
|
"fs-extra": "^9.0.1",
|
|
30
31
|
"inquirer": "^7.3.3",
|
|
32
|
+
"js-yaml": "^4.1.0",
|
|
31
33
|
"listr": "^0.14.3",
|
|
32
34
|
"ncp": "^2.0.0",
|
|
33
35
|
"omelette": "^0.4.15-1",
|
|
34
36
|
"open": "^8.4.0",
|
|
35
37
|
"simple-git": "^3.15.1",
|
|
38
|
+
"tar": "^7.4.3",
|
|
39
|
+
"tough-cookie": "^5.1.2",
|
|
36
40
|
"webpack": "^5.75.0",
|
|
37
41
|
"webpack-cli": "^5.0.1",
|
|
38
42
|
"webpack-dev-server": "^4.11.1",
|
package/schema.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"name" : "BB032",
|
|
4
|
+
"definitions": {
|
|
5
|
+
"query" : ["BB032", "Dashboard", "BPO"]
|
|
6
|
+
},
|
|
7
|
+
"permissions" : {
|
|
8
|
+
"query" : "@BB032"
|
|
9
|
+
},
|
|
10
|
+
"instances" : [
|
|
11
|
+
{
|
|
12
|
+
"definition" : "Dashboard_v1",
|
|
13
|
+
"query" : "solution_reference:BB032"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"definition" : "Dashboard-Files",
|
|
17
|
+
"query" : "*"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"definition" : "Dashboard-Solutions",
|
|
21
|
+
"query" : "BB032"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"definition" : "Business Process",
|
|
25
|
+
"query" : "BB032"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"definition" : "Work Queues",
|
|
29
|
+
"query" : "BB032"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
]
|
package/.tool-versions
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
nodejs 16.20.2
|