cob-cli 2.26.0 → 2.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cob-cli.js +3 -6
- package/bin/handleAutoComplete.js +2 -0
- package/lib/commands/customize.js +98 -81
- package/package.json +1 -1
- package/.gitmodules +0 -27
- package/README.Development.md +0 -294
- package/README.publish.md +0 -10
- package/lib/task_lists/customize_copy.js +0 -51
- package/lib/task_lists/customize_mergeFiles.js +0 -42
- package/lib/task_lists/customize_questions.js +0 -40
package/bin/cob-cli.js
CHANGED
|
@@ -16,12 +16,9 @@ const { upgradeRepo } = require("../lib/commands/upgradeRepo");
|
|
|
16
16
|
program
|
|
17
17
|
.description('CoB Command line to simplify server customizations')
|
|
18
18
|
.usage("command")
|
|
19
|
-
.version(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
.description('CoB Command line to simplify server customizations')
|
|
23
|
-
.usage("command")
|
|
24
|
-
.version( require('../package.json').version,'-v, --version', 'output the current version');
|
|
19
|
+
.version(require('../package.json').version, '-v, --version', 'output the current version')
|
|
20
|
+
.option('--setup','add autocomplete to system profiles')
|
|
21
|
+
.option('--cleanup', 'remove autocomplete from system profiles')
|
|
25
22
|
|
|
26
23
|
program
|
|
27
24
|
.command('init')
|
|
@@ -15,9 +15,11 @@ completion.init()
|
|
|
15
15
|
|
|
16
16
|
// add to system profiles
|
|
17
17
|
if (~process.argv.indexOf('--setup')) {
|
|
18
|
+
console.log("Setting up...")
|
|
18
19
|
completion.setupShellInitFile()
|
|
19
20
|
}
|
|
20
21
|
// remove from system profiles
|
|
21
22
|
if (~process.argv.indexOf('--cleanup')) {
|
|
23
|
+
console.log("Cleaning...")
|
|
22
24
|
completion.cleanupShellInitFile()
|
|
23
25
|
}
|
|
@@ -11,14 +11,14 @@ const fg = require("fast-glob");
|
|
|
11
11
|
const fs = require("fs-extra");
|
|
12
12
|
|
|
13
13
|
/* ************************************************************************ */
|
|
14
|
-
async function customize(
|
|
14
|
+
async function customize(filter, args) {
|
|
15
15
|
try {
|
|
16
16
|
console.log("Customize...");
|
|
17
17
|
checkVersion();
|
|
18
|
-
if (!
|
|
18
|
+
if (!args.force) await checkWorkingCopyCleanliness();
|
|
19
19
|
|
|
20
|
-
let repo = await getCustomizationRepo(
|
|
21
|
-
if (!
|
|
20
|
+
let repo = await getCustomizationRepo(filter,args);
|
|
21
|
+
if (!args.local) await getCustomizationFiles(repo);
|
|
22
22
|
await applyCustomization(repo);
|
|
23
23
|
|
|
24
24
|
console.log( colors.green("\nDone"), "\nCheck changes to your git working tree and try:" );
|
|
@@ -28,31 +28,48 @@ async function customize(customizationArg, otherArgs) {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
module.exports = customize;
|
|
31
|
-
/* ************************************************************************ */
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
)
|
|
32
|
+
/* ************************************************************************ */
|
|
33
|
+
async function getCustomizationRepo(filter, args) {
|
|
34
|
+
const { xdgData } = await import("xdg-basedir");
|
|
35
|
+
const cacheCustomizations = path.resolve(xdgData,"cob-cli","customizations.json")
|
|
36
|
+
|
|
37
|
+
let customizationRepos;
|
|
38
|
+
let customizationNameQuery = "customize. " + (filter ? filter : "");
|
|
39
|
+
if (args.local) {
|
|
40
|
+
customizationRepos = JSON.parse(fs.readFileSync(cacheCustomizations))
|
|
41
|
+
if (filter) {
|
|
42
|
+
customizationRepos = customizationRepos.filter(repo => repo.name.indexOf(filter) != -1)
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
// Get list of relevant customizations from github
|
|
46
|
+
let response = await axios.get(
|
|
47
|
+
"https://api.github.com/search/repositories?q=" +
|
|
48
|
+
customizationNameQuery + "+in:name+org:cob",
|
|
49
|
+
{ headers: { Accept: "application/json", "Accept-Encoding": "identity" } }
|
|
50
|
+
)
|
|
51
|
+
customizationRepos = response.data.items
|
|
52
|
+
}
|
|
41
53
|
|
|
42
|
-
if
|
|
43
|
-
|
|
54
|
+
// Check if there's at least one customization
|
|
55
|
+
if (customizationRepos.length == 0) throw new Error("\nError: ".red + " no customization found\n");
|
|
44
56
|
|
|
45
57
|
// Asks for customization to apply
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if(
|
|
58
|
+
if (args.cache && args.local) {
|
|
59
|
+
throw new Error("\nError: ".red + " incompatible options, --local AND --cache\n");
|
|
60
|
+
} else if(args.cache) {
|
|
49
61
|
console.log("Caching all customizations...");
|
|
50
62
|
for( let repo of customizationRepos) {
|
|
51
63
|
await getCustomizationFiles(repo);
|
|
52
64
|
}
|
|
65
|
+
fs.writeFileSync( cacheCustomizations,
|
|
66
|
+
JSON.stringify(customizationRepos, null, 2),
|
|
67
|
+
(err) => {
|
|
68
|
+
if (err) console.log( "Error writing " + cacheCustomizations + ":", err.message);
|
|
69
|
+
}
|
|
70
|
+
)
|
|
53
71
|
}
|
|
54
72
|
|
|
55
|
-
|
|
56
73
|
let answer = await inquirer.prompt([
|
|
57
74
|
{
|
|
58
75
|
type: "list",
|
|
@@ -66,6 +83,7 @@ async function getCustomizationRepo(arg,otherArgs) {
|
|
|
66
83
|
return customizationRepos.find((repo) => repo.name == answer.customization);
|
|
67
84
|
}
|
|
68
85
|
|
|
86
|
+
/* ************************************************************************ */
|
|
69
87
|
async function getCustomizationFiles(repo) {
|
|
70
88
|
const { xdgData } = await import("xdg-basedir");
|
|
71
89
|
const baseDir = process.cwd();
|
|
@@ -74,39 +92,41 @@ async function getCustomizationFiles(repo) {
|
|
|
74
92
|
|
|
75
93
|
process.chdir(cacheDir);
|
|
76
94
|
if (!fs.existsSync(path.resolve(cacheDir,repo.name))) {
|
|
77
|
-
console.log("git
|
|
95
|
+
console.log(" git " + repo.ssh_url);
|
|
78
96
|
await git().clone(repo.ssh_url);
|
|
79
97
|
} else {
|
|
80
|
-
console.log("git pull " + repo.ssh_url);
|
|
98
|
+
console.log(" git pull " + repo.ssh_url);
|
|
81
99
|
process.chdir(repo.name);
|
|
82
100
|
await git().pull();
|
|
83
101
|
}
|
|
84
102
|
process.chdir(baseDir);
|
|
85
103
|
}
|
|
86
104
|
|
|
105
|
+
/* ************************************************************************ */
|
|
87
106
|
async function applyCustomization(repo) {
|
|
88
107
|
console.log("\nApplying " + repo.name + " customization ...");
|
|
89
108
|
|
|
90
109
|
// Get customization info from convention defined file (customize.js)
|
|
91
110
|
const { xdgData } = await import("xdg-basedir");
|
|
92
|
-
const
|
|
111
|
+
const customizationPath = path.resolve( xdgData, "cob-cli", repo.name);
|
|
112
|
+
const customizationFile = path.resolve( customizationPath, "customize.js");
|
|
93
113
|
if (!fs.existsSync(customizationFile))
|
|
94
114
|
throw new Error("\nError: ".red + " no customize.js file found\n");
|
|
95
115
|
|
|
96
116
|
let customization = (await import(customizationFile)).default;
|
|
97
117
|
|
|
98
|
-
// Asks
|
|
99
|
-
let
|
|
118
|
+
// Asks questions, if configuration exists
|
|
119
|
+
let answers = {};
|
|
100
120
|
if (customization.questions) {
|
|
101
|
-
|
|
121
|
+
answers = await inquirer.prompt(customization.questions);
|
|
102
122
|
}
|
|
103
123
|
|
|
104
124
|
// Apply specific customization, if it exists, otherwise use default actions
|
|
105
125
|
if (customization.actions) {
|
|
106
|
-
customization.actions(repo.name,
|
|
126
|
+
customization.actions(repo.name, answers, copy, mergeFiles);
|
|
107
127
|
} else {
|
|
108
128
|
// Default actions
|
|
109
|
-
await copy(
|
|
129
|
+
await copy(repo.name, process.cwd(), answers);
|
|
110
130
|
await mergeFiles(repo.name);
|
|
111
131
|
}
|
|
112
132
|
|
|
@@ -114,62 +134,63 @@ async function applyCustomization(repo) {
|
|
|
114
134
|
updateCustomizationsVersions(repo.name, customization.version);
|
|
115
135
|
}
|
|
116
136
|
|
|
117
|
-
|
|
137
|
+
/* ************************************************************************ */
|
|
138
|
+
async function copy(repoName, target, substitutions = {}) {
|
|
118
139
|
// https://www.npmtrends.com/copyfiles-vs-cpx-vs-ncp-vs-npm-build-tools
|
|
119
140
|
// https://www.npmjs.com/package/ncp
|
|
120
141
|
// https://www.npmjs.com/package/copyfiles
|
|
121
142
|
|
|
122
|
-
|
|
143
|
+
let source
|
|
144
|
+
if(repoName.indexOf("/") == 0) {
|
|
145
|
+
// Based of repoName starting with "/" we assume this is already a fullpath
|
|
146
|
+
source = repoName;
|
|
147
|
+
} else {
|
|
148
|
+
// Otherwise assume repoName on standard cob-cli xdgData path
|
|
149
|
+
const { xdgData } = await import("xdg-basedir");
|
|
150
|
+
source = path.resolve( xdgData, "cob-cli", repoName);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
console.log(" Copying template files ...");
|
|
123
154
|
|
|
124
|
-
let srcPath = path.resolve(process.cwd(), source);
|
|
125
|
-
// let excludedFiles = RegExp(srcPath + ".*/node_modules/");
|
|
126
155
|
let excludedFiles = RegExp(
|
|
127
156
|
"(" +
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
157
|
+
source + "/\\.git.*" +
|
|
158
|
+
"|" +
|
|
159
|
+
source + "/README.*" +
|
|
160
|
+
"|" +
|
|
161
|
+
source + "/customize.js" +
|
|
162
|
+
"|" +
|
|
163
|
+
source + ".*/node_modules/" +
|
|
164
|
+
")"
|
|
134
165
|
);
|
|
135
166
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
const files = await fg(["**/*.__*__.*"], { onlyFiles: true, dot: true });
|
|
163
|
-
files.forEach((file) => {
|
|
164
|
-
if (file.match(/__MERGE__/)) return;
|
|
165
|
-
fs.renameSync(
|
|
166
|
-
file,
|
|
167
|
-
file.replace(/__.+__/g, (m) => substitutions[m])
|
|
168
|
-
);
|
|
169
|
-
});
|
|
170
|
-
});
|
|
167
|
+
// Source is on cob-cli repo and Destination on the server repo
|
|
168
|
+
await ncp(
|
|
169
|
+
source,
|
|
170
|
+
target,
|
|
171
|
+
{
|
|
172
|
+
clobber: true,
|
|
173
|
+
filter: (src) => src.match(excludedFiles) == null,
|
|
174
|
+
// TODO: comentado porque não funciona a copiar os ficheiros binários (em concreto as font no template/dashboards/dash)
|
|
175
|
+
// transform(read, write) {
|
|
176
|
+
// const replaceVars = new Transform({
|
|
177
|
+
// transform: (chunk, encoding, done) => done(null,chunk.toString().replace(/__.+__/g, m => substitutions[m]))
|
|
178
|
+
// })
|
|
179
|
+
// read.pipe(replaceVars).pipe(write)
|
|
180
|
+
// }
|
|
181
|
+
},
|
|
182
|
+
(error) => error && error.map((e) => e.message).join("\n")
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const dryrun = await fg(["**/*__*__*"], { onlyFiles: false, dot: true }); //Just to give time for OS to stabilize
|
|
186
|
+
const files = await fg(["**/*__*__*"], { onlyFiles: false, dot: true });
|
|
187
|
+
for(let file of files.filter(name => name.indexOf("node_modules") == -1)) {
|
|
188
|
+
if (file.match(/__MERGE__/)) return;
|
|
189
|
+
fs.renameSync( file, file.replace(/__(.+)__/g, (match,g1) => substitutions[g1]) );
|
|
190
|
+
}
|
|
171
191
|
}
|
|
172
192
|
|
|
193
|
+
/* ************************************************************************ */
|
|
173
194
|
async function mergeFiles(block) {
|
|
174
195
|
const mergeFiles = await fg(["**/*.__MERGE__.*"], {
|
|
175
196
|
onlyFiles: false,
|
|
@@ -187,6 +208,7 @@ async function mergeFiles(block) {
|
|
|
187
208
|
}
|
|
188
209
|
let prodFileContent = fs.readFileSync(prodFile).toString();
|
|
189
210
|
let mergeFileContent = fs.readFileSync(mergeFile).toString();
|
|
211
|
+
// With comments we support JS, CSS, GROOVY
|
|
190
212
|
let startStr = "/* COB-CLI START " + blockMark + " */\n";
|
|
191
213
|
let endStr = "\n/* COB-CLI END " + blockMark + " */\n";
|
|
192
214
|
|
|
@@ -210,28 +232,23 @@ async function mergeFiles(block) {
|
|
|
210
232
|
}
|
|
211
233
|
}
|
|
212
234
|
|
|
235
|
+
/* ************************************************************************ */
|
|
213
236
|
function updateCustomizationsVersions(customizationKey, version) {
|
|
214
237
|
const customizationsVersionsFile = "customizations.json";
|
|
215
238
|
let customizationsVersions;
|
|
216
239
|
try {
|
|
217
|
-
|
|
218
|
-
customizationsVersionsFile
|
|
219
|
-
);
|
|
240
|
+
const customizationsVersionsRawData = fs.readFileSync(customizationsVersionsFile);
|
|
220
241
|
customizationsVersions = JSON.parse(customizationsVersionsRawData);
|
|
221
242
|
} catch (err) {
|
|
222
243
|
customizationsVersions = {};
|
|
223
244
|
}
|
|
224
245
|
customizationsVersions[customizationKey] = version;
|
|
225
246
|
|
|
226
|
-
fs.
|
|
247
|
+
fs.writeFileSync(
|
|
227
248
|
customizationsVersionsFile,
|
|
228
249
|
JSON.stringify(customizationsVersions, null, 2),
|
|
229
250
|
(err) => {
|
|
230
|
-
if (err)
|
|
231
|
-
console.log(
|
|
232
|
-
"Error writing " + customizationsVersionsFile + ":",
|
|
233
|
-
err.message
|
|
234
|
-
);
|
|
251
|
+
if (err) console.log( "Error writing " + customizationsVersionsFile + ":", err.message );
|
|
235
252
|
}
|
|
236
253
|
);
|
|
237
254
|
}
|
package/package.json
CHANGED
package/.gitmodules
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
[submodule "templates/keywords/image"]
|
|
2
|
-
path = templates/keywords/image
|
|
3
|
-
url = https://github.com/cob/customize.keywords.image.git
|
|
4
|
-
[submodule "templates/keywords/styleResults"]
|
|
5
|
-
path = templates/keywords/styleResults
|
|
6
|
-
url = git@github.com:cob/customize.keywords.styleResults.git
|
|
7
|
-
[submodule "templates/keywords/log"]
|
|
8
|
-
path = templates/keywords/log
|
|
9
|
-
url = git@github.com:cob/customize.keywords.log.git
|
|
10
|
-
[submodule "templates/keywords/calc"]
|
|
11
|
-
path = templates/keywords/calc
|
|
12
|
-
url = git@github.com:cob/customize.keywords.calc.git
|
|
13
|
-
[submodule "templates/keywords/audit"]
|
|
14
|
-
path = templates/keywords/audit
|
|
15
|
-
url = git@github.com:cob/customize.keywords.audit.git
|
|
16
|
-
[submodule "templates/frontend/common"]
|
|
17
|
-
path = templates/frontend/common
|
|
18
|
-
url = git@github.com:cob/customize.frontend.common.git
|
|
19
|
-
[submodule "templates/frontend/formatList/currency"]
|
|
20
|
-
path = templates/frontend/formatList/currency
|
|
21
|
-
url = git@github.com:cob/customize.frontend.formatList.currency.git
|
|
22
|
-
[submodule "templates/dashboards/dash"]
|
|
23
|
-
path = templates/dashboards/dash
|
|
24
|
-
url = git@github.com:cob/customize.dashboard.dash.git
|
|
25
|
-
[submodule "templates/keywords/kibana"]
|
|
26
|
-
path = templates/keywords/kibana
|
|
27
|
-
url = git@github.com:cob/customize.keywords.kibana.git
|
package/README.Development.md
DELETED
|
@@ -1,294 +0,0 @@
|
|
|
1
|
-
# Templates
|
|
2
|
-
|
|
3
|
-
Mainly for `cob-cli customize` purposes, the `templates` directory has all necessary files to customize a CoB application in standard/predefined ways.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
## cob-dashboard-template
|
|
7
|
-
|
|
8
|
-
These are the base files needed to have our recomend dashboard infra-structure. It's preconfigured with **vue**, **vuetify** , **@cob/rest-api-wrapper** and **@cob/dashboard-info** dependencies.
|
|
9
|
-
|
|
10
|
-
The steps necessary to achieve this final configuration are the following:
|
|
11
|
-
|
|
12
|
-
### 1. `vue create cob-dashboard-template`
|
|
13
|
-
|
|
14
|
-
The only option to select is *use version 2* of vue, ie, no babel, no lint, no test, etc.
|
|
15
|
-
|
|
16
|
-
From the resulting directory we will only use 1 file, `package.json`.
|
|
17
|
-
|
|
18
|
-
In 2021.04.14 the result was:
|
|
19
|
-
```json
|
|
20
|
-
{
|
|
21
|
-
"name": "cob-dashboard-template",
|
|
22
|
-
"version": "0.1.0",
|
|
23
|
-
"private": true,
|
|
24
|
-
"scripts": {
|
|
25
|
-
"serve": "vue-cli-service serve",
|
|
26
|
-
"build": "vue-cli-service build"
|
|
27
|
-
},
|
|
28
|
-
"dependencies": {
|
|
29
|
-
"vue": "^2.6.11"
|
|
30
|
-
},
|
|
31
|
-
"devDependencies": {
|
|
32
|
-
"@vue/cli-service": "~4.5.0",
|
|
33
|
-
"vue-template-compiler": "^2.6.11"
|
|
34
|
-
},
|
|
35
|
-
"browserslist": [
|
|
36
|
-
"> 1%",
|
|
37
|
-
"last 2 versions",
|
|
38
|
-
"not dead"
|
|
39
|
-
]
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
### 2. `vue add vuetify`
|
|
45
|
-
|
|
46
|
-
The choosen options were:
|
|
47
|
-
```
|
|
48
|
-
? Choose a preset: Configure (advanced)
|
|
49
|
-
? Use a pre-made template? (will replace App.vue and HelloWorld.vue) Yes
|
|
50
|
-
? Use custom theme? No
|
|
51
|
-
? Use custom properties (CSS variables)? No
|
|
52
|
-
? Select icon font Material Design Icons
|
|
53
|
-
? Use fonts as a dependency (for Electron or offline)? No
|
|
54
|
-
? Use a-la-carte components? No
|
|
55
|
-
? Use babel/polyfill? No
|
|
56
|
-
? Select locale English
|
|
57
|
-
```
|
|
58
|
-
This command will add the following lines to `package.json`
|
|
59
|
-
|
|
60
|
-
```json
|
|
61
|
-
"vuetify": "^2.4.0"
|
|
62
|
-
"vue-cli-plugin-vuetify": "~2.3.1",
|
|
63
|
-
```
|
|
64
|
-
with the following end result
|
|
65
|
-
```json
|
|
66
|
-
{
|
|
67
|
-
"name": "cob-dashboard-template",
|
|
68
|
-
"version": "0.1.0",
|
|
69
|
-
"private": true,
|
|
70
|
-
"scripts": {
|
|
71
|
-
"serve": "vue-cli-service serve",
|
|
72
|
-
"build": "vue-cli-service build"
|
|
73
|
-
},
|
|
74
|
-
"dependencies": {
|
|
75
|
-
"vue": "^2.6.11",
|
|
76
|
-
"vuetify": "^2.4.0"
|
|
77
|
-
},
|
|
78
|
-
"devDependencies": {
|
|
79
|
-
"@vue/cli-service": "~4.5.0",
|
|
80
|
-
"vue-cli-plugin-vuetify": "~2.3.1",
|
|
81
|
-
"vue-template-compiler": "^2.6.11"
|
|
82
|
-
},
|
|
83
|
-
"browserslist": [
|
|
84
|
-
"> 1%",
|
|
85
|
-
"last 2 versions",
|
|
86
|
-
"not dead",
|
|
87
|
-
"not ie <= 10"
|
|
88
|
-
]
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
Two other files are relevant for the end result:
|
|
93
|
-
|
|
94
|
-
`src/main.js`
|
|
95
|
-
```javascript
|
|
96
|
-
import Vue from 'vue'
|
|
97
|
-
import App from './App.vue'
|
|
98
|
-
import vuetify from './plugins/vuetify';
|
|
99
|
-
|
|
100
|
-
Vue.config.productionTip = false
|
|
101
|
-
|
|
102
|
-
new Vue({
|
|
103
|
-
vuetify,
|
|
104
|
-
render: function (h) { return h(App) }
|
|
105
|
-
}).$mount('#app')
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
`src/plugins/vuetify.js`
|
|
109
|
-
```javascript
|
|
110
|
-
import Vue from 'vue';
|
|
111
|
-
import Vuetify from 'vuetify';
|
|
112
|
-
import 'vuetify/dist/vuetify.min.css';
|
|
113
|
-
|
|
114
|
-
Vue.use(Vuetify);
|
|
115
|
-
|
|
116
|
-
export default new Vuetify({
|
|
117
|
-
});
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### 3. Delete all files irrelevant files
|
|
121
|
-
For our app we only need the files we specified above (`package.json`, `src/main.js` and `src/plugins/vuetify.js`)
|
|
122
|
-
|
|
123
|
-
### 4. Add the cob dependencies
|
|
124
|
-
```
|
|
125
|
-
npm i --save @cob/rest-api-wrapper
|
|
126
|
-
npm i --save @cob/dashboard-info
|
|
127
|
-
npm i --save @cob/ui-vue-components
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
This adds the following lines to `package.json` (in 2021.04.14):
|
|
131
|
-
```json
|
|
132
|
-
"dependencies": {
|
|
133
|
-
"@cob/dashboard-info": "^2.2.5",
|
|
134
|
-
"@cob/rest-api-wrapper": "^2.1.6",
|
|
135
|
-
"@cob/ui-vue-components": "^4.1.0",
|
|
136
|
-
```
|
|
137
|
-
`@cob/ui-vue-components` needs to be loaded by vue. For this add `src/plugins/cobUiVueComponents.js` and change `src/main.js`:
|
|
138
|
-
|
|
139
|
-
`src/plugins/cobUiVueComponents.js`
|
|
140
|
-
```javascript
|
|
141
|
-
import Vue from 'vue';
|
|
142
|
-
import CobUiVueComponents from '@cob/ui-vue-components';
|
|
143
|
-
|
|
144
|
-
Vue.use(CobUiVueComponents);
|
|
145
|
-
|
|
146
|
-
export default CobUiVueComponents
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
`src/main.js`
|
|
150
|
-
```javascript
|
|
151
|
-
import Vue from 'vue'
|
|
152
|
-
import App from './App.vue'
|
|
153
|
-
import vuetify from './plugins/vuetify';
|
|
154
|
-
import cobUiVueComponents from './plugins/cobUiVueComponents';
|
|
155
|
-
|
|
156
|
-
Vue.config.productionTip = false
|
|
157
|
-
|
|
158
|
-
new Vue({
|
|
159
|
-
vuetify,
|
|
160
|
-
cobUiVueComponents,
|
|
161
|
-
render: function (h) { return h(App) }
|
|
162
|
-
}).$mount('#app')
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
### 5. Add an `App.vue` example
|
|
166
|
-
A simple page that uses all libs and adds a splash screen with the relevant links.
|
|
167
|
-
```html
|
|
168
|
-
<template>
|
|
169
|
-
<v-app>
|
|
170
|
-
<v-main>
|
|
171
|
-
<HelloWorld
|
|
172
|
-
:msg='"Welcome " + userInfo.username'
|
|
173
|
-
:extraInfo='domainCount.value ? "(your domain 1 has " + domainCount.value + " instances)" : "(no backend info)"'
|
|
174
|
-
/>
|
|
175
|
-
</v-main>
|
|
176
|
-
</v-app>
|
|
177
|
-
</template>
|
|
178
|
-
|
|
179
|
-
<script>
|
|
180
|
-
import { umLoggedin } from '@cob/rest-api-wrapper';
|
|
181
|
-
import { domainCount } from '@cob/dashboard-info';
|
|
182
|
-
|
|
183
|
-
export default {
|
|
184
|
-
name: 'App',
|
|
185
|
-
data: () => ({
|
|
186
|
-
userInfo : {},
|
|
187
|
-
domainCount: domainCount(1),
|
|
188
|
-
}),
|
|
189
|
-
created() {
|
|
190
|
-
umLoggedin().then( userInfo => this.userInfo = userInfo )
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
|
-
</script>
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### 6. Add webpack configuration
|
|
197
|
-
To run any (known) vue aplication in a CoB server there are only two files necessary to add to an existing vue project:
|
|
198
|
-
* `vue.config.js` - this file is the vue version os `webpack.config.js` and it has 2 purposes:
|
|
199
|
-
1. serve a version of the app with hot-reload, during development.
|
|
200
|
-
|
|
201
|
-
You can start serving the app directly on the app directory, using `npm run serve`, or on the top cob-cli project directory, with `cob-cli test -d <app dir name>`. This file will support both methods and will get the server to proxy the requests to from the top directory `.server` file. If this file is not present the `learning.cultofbits.com` server will be used.
|
|
202
|
-
|
|
203
|
-
The entry point is the `http://localhost:8041/<app dir name>/dashboard.html` and all requests for `/<app dir name>/**` will be served locally. All CoB urls will be proxied to the specified server.
|
|
204
|
-
|
|
205
|
-
1. build the files necessary to deploy the aplication to production
|
|
206
|
-
|
|
207
|
-
The build process is done by `npm run build` and it will produce in `./dist` all the files that need to be copied to the server (which will be done by `cob-cli deploy`).
|
|
208
|
-
|
|
209
|
-
While being executed this code will also set a `rmIntegrated` variable that flags if it's building the final files or serving the files (to be usedby the `dashboard.html`).
|
|
210
|
-
|
|
211
|
-
* `src/dashboard.html`
|
|
212
|
-
|
|
213
|
-
because CoB servers will look at a `#/cob.custom-resource/<...>/<dashboard name>` URL and try to load `/recordm/localresource/<dashboard name>/dist/dashboard.html` this file will suport both be built for that purpose and, simultaneasly, be served locally, with the extra HTML necessary tags.
|
|
214
|
-
|
|
215
|
-
It will produce an output for serving localy or production based on the `rmIntegrated` webpack variable.
|
|
216
|
-
|
|
217
|
-
### 7. Test the end result
|
|
218
|
-
After these steps you can:
|
|
219
|
-
```
|
|
220
|
-
$ cd templates/cob-dashboard-template
|
|
221
|
-
$ npm i
|
|
222
|
-
$ npm run serve
|
|
223
|
-
```
|
|
224
|
-
it will use the `learning.cultofbits.com` site as backend and display the inteded example.
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
# Debugging
|
|
229
|
-
Using VSCode you can debug the command line behaviour. The file `.vscode/launch.json` has the commands and arguments that will be used. Note that the `cob-cli` command will run on the on the directories specified in this file.
|
|
230
|
-
|
|
231
|
-
# TODO:
|
|
232
|
-
* Support manual mode deploy (basically the copy intructions and a deploy process script)
|
|
233
|
-
* Consider adding autocomplete to cob-cli (see package [commander-auto-complete](https://www.npmjs.com/package/commander-auto-complete)), specifically:
|
|
234
|
-
> _If you want this done automatically for you, you could add that script to npm lifecycle hooks_
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
# References:
|
|
238
|
-
|
|
239
|
-
## Packages
|
|
240
|
-
* Used:
|
|
241
|
-
* https://www.npmjs.com/package/commander
|
|
242
|
-
* https://www.npmjs.com/package/inquirer
|
|
243
|
-
* https://www.npmjs.com/package/listr
|
|
244
|
-
* https://www.npmjs.com/package/simple-git
|
|
245
|
-
* https://www.npmjs.com/package/execa
|
|
246
|
-
* https://www.npmjs.com/package/fs-extra
|
|
247
|
-
|
|
248
|
-
* Potentials:
|
|
249
|
-
* https://www.npmjs.com/package/copy-template-dir
|
|
250
|
-
* https://www.npmjs.com/package/commander-auto-complete
|
|
251
|
-
|
|
252
|
-
## About npm cli
|
|
253
|
-
* Base info about adding node cmds to path environment :
|
|
254
|
-
* https://medium.com/@thatisuday/creating-cli-executable-global-npm-module-5ef734febe32
|
|
255
|
-
* Additional info about supporting multiple commands and parsing arguments:
|
|
256
|
-
* https://itnext.io/making-cli-app-with-ease-using-commander-js-and-inquirer-js-f3bbd52977ac
|
|
257
|
-
* About inquirer e listr
|
|
258
|
-
* https://www.twilio.com/blog/how-to-build-a-cli-with-node-js
|
|
259
|
-
* NPM package publishing:
|
|
260
|
-
* https://zellwk.com/blog/publish-to-npm/
|
|
261
|
-
* Others:
|
|
262
|
-
* https://www.sitepoint.com/javascript-command-line-interface-cli-node-js/
|
|
263
|
-
* https://www.keithcirkel.co.uk/how-to-use-npm-as-a-build-tool/
|
|
264
|
-
* https://nodesource.com/blog/node-js-powerful-beautiful-clis
|
|
265
|
-
|
|
266
|
-
## About using commit messages to manage semantic-release:
|
|
267
|
-
* https://www.conventionalcommits.org/en/v1.0.0/
|
|
268
|
-
* https://github.com/semantic-release/semantic-release
|
|
269
|
-
* https://github.com/semantic-release/semantic-release/blob/master/docs/extending/plugins-list.md
|
|
270
|
-
* https://github.com/oleg-koval/semantic-release-npm-github-publish (from [Shareable configurations list](https://github.com/semantic-release/semantic-release/blob/master/docs/extending/shareable-configurations-list.md))
|
|
271
|
-
* https://marketplace.visualstudio.com/items?itemName=vivaxy.vscode-conventional-commits
|
|
272
|
-
* https://blog.usejournal.com/semantic-release-with-nodejs-full-gitlab-ci-flow-dfee9639f20f
|
|
273
|
-
|
|
274
|
-
## About using git for production deployments
|
|
275
|
-
* About deploys:
|
|
276
|
-
* https://dev.to/becodeorg/deploy-an-application-automatically-using-github-hooks-50fd
|
|
277
|
-
* https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
|
|
278
|
-
* https://devcenter.heroku.com/articles/git
|
|
279
|
-
* https://wpengine.com/support/git/
|
|
280
|
-
* https://wpengine.com/support/deploying-code-with-bitbucket-pipelines-wp-engine/
|
|
281
|
-
* https://security.stackexchange.com/questions/45452/is-using-git-for-deploying-a-bad-practice
|
|
282
|
-
* https://www.git-scm.com/docs/githooks
|
|
283
|
-
* Proposed git Workflow:
|
|
284
|
-
* https://githubflow.github.io (in contrast with https://nvie.com/posts/a-successful-git-branching-model/)
|
|
285
|
-
* https://gist.github.com/cjsteel/5bdab49c97ecacb67904056ccdcb956d
|
|
286
|
-
|
|
287
|
-
## Improving vue boilerplate
|
|
288
|
-
* https://gitlab.com/cob/vue-cli-preset
|
|
289
|
-
* https://gitlab.com/cob/solutions-template
|
|
290
|
-
* https://gitlab.com/cob/vue-cli-plugin-dashboard
|
|
291
|
-
* https://medium.com/justfrontendthings/how-to-create-and-publish-your-own-vuejs-component-library-on-npm-using-vue-cli-28e60943eed3
|
|
292
|
-
* https://cli.vuejs.org/dev-guide/plugin-dev.html#discoverability
|
|
293
|
-
* https://javascript.info/promise-chaining#tasks
|
|
294
|
-
* https://github.com/vuejs/vue-cli/tree/9c1e797ac6c25b5827403693e018eb199300d067/packages/%40vue/cli-service/generator/template/src
|
package/README.publish.md
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
const ncp = require('ncp');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const {Transform} = require('stream')
|
|
4
|
-
|
|
5
|
-
// https://www.npmtrends.com/copyfiles-vs-cpx-vs-ncp-vs-npm-build-tools
|
|
6
|
-
// https://www.npmjs.com/package/ncp
|
|
7
|
-
// https://www.npmjs.com/package/copyfiles
|
|
8
|
-
|
|
9
|
-
function copy(source, target, substitutions = {}) {
|
|
10
|
-
console.log(" Copying template files to '" + target + "'...")
|
|
11
|
-
|
|
12
|
-
let srcPath = path.resolve(__dirname,source)
|
|
13
|
-
let nodeModuleRegex = RegExp(srcPath+".*/node_modules/")
|
|
14
|
-
|
|
15
|
-
return new Promise(async (resolve) => {
|
|
16
|
-
// Source is on cob-cli repo and Destination on the server repo
|
|
17
|
-
await ncp(path.resolve(__dirname,source),
|
|
18
|
-
target,
|
|
19
|
-
{
|
|
20
|
-
clobber: true,
|
|
21
|
-
filter: (src) => src.match(nodeModuleRegex) == null,
|
|
22
|
-
// TODO: comentado porque não funciona a copiar os ficheiros binários (em concreto as font no template/dashboards/dash)
|
|
23
|
-
// transform(read, write) {
|
|
24
|
-
// const replaceVars = new Transform({
|
|
25
|
-
// transform: (chunk, encoding, done) => done(null,chunk.toString().replace(/__.+__/g, m => substitutions[m]))
|
|
26
|
-
// })
|
|
27
|
-
// read.pipe(replaceVars).pipe(write)
|
|
28
|
-
// }
|
|
29
|
-
},
|
|
30
|
-
(error,x) => {
|
|
31
|
-
if (error) {
|
|
32
|
-
// Error is an array of problems
|
|
33
|
-
resolve(error.map(e => e.message).join("\n"));
|
|
34
|
-
} else {
|
|
35
|
-
resolve();
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
const { renameSync } = require('fs');
|
|
41
|
-
const fg = require('fast-glob');
|
|
42
|
-
|
|
43
|
-
const files = await fg(['**/*.__*__.*'], { onlyFiles: true, dot: true });
|
|
44
|
-
files
|
|
45
|
-
.forEach(file => {
|
|
46
|
-
if(file.match(/__MERGE__/)) return
|
|
47
|
-
renameSync(file, file.replace(/__.+__/g, m => substitutions[m]));
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
exports.copy = copy;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
async function mergeFiles(block) {
|
|
3
|
-
const fg = require('fast-glob');
|
|
4
|
-
const fs = require('fs-extra');
|
|
5
|
-
const mergeFiles = await fg(['**/*.__MERGE__.*'], { onlyFiles: false, dot: true });
|
|
6
|
-
for (let mergeFile of mergeFiles) {
|
|
7
|
-
let prodFile = mergeFile.replace(/\.__MERGE__/, "");
|
|
8
|
-
let blockMark = (block == undefined ? "" : block)
|
|
9
|
-
if (!fs.existsSync(prodFile)) {
|
|
10
|
-
// If prod file does not exist creates it
|
|
11
|
-
console.log(" Creating " + prodFile)
|
|
12
|
-
fs.closeSync(fs.openSync(prodFile, 'w'));
|
|
13
|
-
} else {
|
|
14
|
-
console.log(" Merging " + prodFile + " " + block)
|
|
15
|
-
}
|
|
16
|
-
let prodFileContent = fs.readFileSync(prodFile).toString();
|
|
17
|
-
let mergeFileContent = fs.readFileSync(mergeFile).toString();
|
|
18
|
-
let startStr = '/* COB-CLI START Customization ' + blockMark + ' */\n';
|
|
19
|
-
let endStr = '\n/* COB-CLI END Customization ' + blockMark + ' */\n';
|
|
20
|
-
|
|
21
|
-
if (prodFileContent.indexOf(startStr) < 0) {
|
|
22
|
-
// If previous customization does not exist
|
|
23
|
-
prodFileContent = startStr
|
|
24
|
-
+ mergeFileContent
|
|
25
|
-
+ endStr
|
|
26
|
-
+ prodFileContent;
|
|
27
|
-
} else {
|
|
28
|
-
// If previous customization exists
|
|
29
|
-
let beforeMerge = prodFileContent.indexOf(startStr);
|
|
30
|
-
let afterMerge = prodFileContent.indexOf(endStr) + endStr.length;
|
|
31
|
-
prodFileContent = prodFileContent.substring(0, beforeMerge)
|
|
32
|
-
+ startStr
|
|
33
|
-
+ mergeFileContent
|
|
34
|
-
+ endStr
|
|
35
|
-
+ prodFileContent.substring(afterMerge);
|
|
36
|
-
}
|
|
37
|
-
fs.writeFileSync(prodFile, prodFileContent);
|
|
38
|
-
|
|
39
|
-
fs.unlinkSync(mergeFile);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
exports.mergeFiles = mergeFiles;
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
exports.definitionNameQuestion = {
|
|
2
|
-
type: 'input',
|
|
3
|
-
name: 'name',
|
|
4
|
-
message: 'What\'s the name of the definition?',
|
|
5
|
-
description: 'the name of the definition listing to customize'
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
exports.dashboardNameQuestion = {
|
|
9
|
-
type: 'input',
|
|
10
|
-
name: 'name',
|
|
11
|
-
message: 'What name for the url?',
|
|
12
|
-
description: 'a valid name consist of one Word composed of letters and numbers',
|
|
13
|
-
validate: function (value) {
|
|
14
|
-
var pass = value.match(
|
|
15
|
-
/^[-0-9a-bA-Z]+$/i
|
|
16
|
-
);
|
|
17
|
-
if (pass) {
|
|
18
|
-
return true;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return 'Only letters and numbers name, at least one';
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
exports.dashboardNameQuestion2 = {
|
|
26
|
-
type: 'input',
|
|
27
|
-
name: 'name2',
|
|
28
|
-
message: 'What name for the url2?',
|
|
29
|
-
description: 'a valid name consist of one Word composed of letters and numbers',
|
|
30
|
-
validate: function (value) {
|
|
31
|
-
var pass = value.match(
|
|
32
|
-
/^[-0-9a-bA-Z]+$/i
|
|
33
|
-
);
|
|
34
|
-
if (pass) {
|
|
35
|
-
return true;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return 'Only letters and numbers name, at least one';
|
|
39
|
-
}
|
|
40
|
-
};
|