cob-cli 2.26.0 → 2.27.1
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 +85 -79
- 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,31 +92,33 @@ 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
118
|
// Asks options, if configuration exists
|
|
99
|
-
let
|
|
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
|
|
@@ -106,7 +126,7 @@ async function applyCustomization(repo) {
|
|
|
106
126
|
customization.actions(repo.name, options, copy, mergeFiles);
|
|
107
127
|
} else {
|
|
108
128
|
// Default actions
|
|
109
|
-
await copy(
|
|
129
|
+
await copy(customizationPath, process.cwd(), answers);
|
|
110
130
|
await mergeFiles(repo.name);
|
|
111
131
|
}
|
|
112
132
|
|
|
@@ -114,62 +134,53 @@ async function applyCustomization(repo) {
|
|
|
114
134
|
updateCustomizationsVersions(repo.name, customization.version);
|
|
115
135
|
}
|
|
116
136
|
|
|
117
|
-
|
|
137
|
+
/* ************************************************************************ */
|
|
138
|
+
async function copy(source, 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
|
-
console.log(" Copying template files
|
|
143
|
+
console.log(" Copying template files ...");
|
|
123
144
|
|
|
124
|
-
let srcPath = path.resolve(process.cwd(), source);
|
|
125
|
-
// let excludedFiles = RegExp(srcPath + ".*/node_modules/");
|
|
126
145
|
let excludedFiles = RegExp(
|
|
127
146
|
"(" +
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
147
|
+
source + "/\\.git.*" +
|
|
148
|
+
"|" +
|
|
149
|
+
source + "/README.*" +
|
|
150
|
+
"|" +
|
|
151
|
+
source + "/customize.js" +
|
|
152
|
+
"|" +
|
|
153
|
+
source + ".*/node_modules/" +
|
|
154
|
+
")"
|
|
134
155
|
);
|
|
135
156
|
|
|
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
|
-
});
|
|
157
|
+
// Source is on cob-cli repo and Destination on the server repo
|
|
158
|
+
await ncp(
|
|
159
|
+
source,
|
|
160
|
+
target,
|
|
161
|
+
{
|
|
162
|
+
clobber: true,
|
|
163
|
+
filter: (src) => src.match(excludedFiles) == null,
|
|
164
|
+
// TODO: comentado porque não funciona a copiar os ficheiros binários (em concreto as font no template/dashboards/dash)
|
|
165
|
+
// transform(read, write) {
|
|
166
|
+
// const replaceVars = new Transform({
|
|
167
|
+
// transform: (chunk, encoding, done) => done(null,chunk.toString().replace(/__.+__/g, m => substitutions[m]))
|
|
168
|
+
// })
|
|
169
|
+
// read.pipe(replaceVars).pipe(write)
|
|
170
|
+
// }
|
|
171
|
+
},
|
|
172
|
+
(error) => error && error.map((e) => e.message).join("\n")
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
const dryrun = await fg(["**/*__*__*"], { onlyFiles: false, dot: true }); //Just to give time for OS to stabilize
|
|
176
|
+
const files = await fg(["**/*__*__*"], { onlyFiles: false, dot: true });
|
|
177
|
+
for(let file of files.filter(name => name.indexOf("node_modules") == -1)) {
|
|
178
|
+
if (file.match(/__MERGE__/)) return;
|
|
179
|
+
fs.renameSync( file, file.replace(/__(.+)__/g, (match,g1) => substitutions[g1]) );
|
|
180
|
+
}
|
|
171
181
|
}
|
|
172
182
|
|
|
183
|
+
/* ************************************************************************ */
|
|
173
184
|
async function mergeFiles(block) {
|
|
174
185
|
const mergeFiles = await fg(["**/*.__MERGE__.*"], {
|
|
175
186
|
onlyFiles: false,
|
|
@@ -210,28 +221,23 @@ async function mergeFiles(block) {
|
|
|
210
221
|
}
|
|
211
222
|
}
|
|
212
223
|
|
|
224
|
+
/* ************************************************************************ */
|
|
213
225
|
function updateCustomizationsVersions(customizationKey, version) {
|
|
214
226
|
const customizationsVersionsFile = "customizations.json";
|
|
215
227
|
let customizationsVersions;
|
|
216
228
|
try {
|
|
217
|
-
|
|
218
|
-
customizationsVersionsFile
|
|
219
|
-
);
|
|
229
|
+
const customizationsVersionsRawData = fs.readFileSync(customizationsVersionsFile);
|
|
220
230
|
customizationsVersions = JSON.parse(customizationsVersionsRawData);
|
|
221
231
|
} catch (err) {
|
|
222
232
|
customizationsVersions = {};
|
|
223
233
|
}
|
|
224
234
|
customizationsVersions[customizationKey] = version;
|
|
225
235
|
|
|
226
|
-
fs.
|
|
236
|
+
fs.writeFileSync(
|
|
227
237
|
customizationsVersionsFile,
|
|
228
238
|
JSON.stringify(customizationsVersions, null, 2),
|
|
229
239
|
(err) => {
|
|
230
|
-
if (err)
|
|
231
|
-
console.log(
|
|
232
|
-
"Error writing " + customizationsVersionsFile + ":",
|
|
233
|
-
err.message
|
|
234
|
-
);
|
|
240
|
+
if (err) console.log( "Error writing " + customizationsVersionsFile + ":", err.message );
|
|
235
241
|
}
|
|
236
242
|
);
|
|
237
243
|
}
|
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
|
-
};
|