@tangelo/tangelo-configuration-toolkit 1.15.1 → 1.16.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/README.md +2 -7
- package/index.js +44 -11
- package/package.json +1 -1
- package/src/cli.js +15 -16
- package/src/modules/build/index.js +9 -13
- package/src/modules/fonto/index.js +0 -2
- package/src/modules/git/index.js +16 -21
package/README.md
CHANGED
|
@@ -26,7 +26,8 @@ Use the `tct` shorthand instead of `tangelo-configuration-toolkit`:
|
|
|
26
26
|
|
|
27
27
|
### Global
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
TCT requires a config file to work: `${userhome}/.tct/appconfig.json`\
|
|
30
|
+
Several commands, like the `deploy` command, require server connection information, which can be stored in here.
|
|
30
31
|
|
|
31
32
|
The contents looks like this (all properties are optional):
|
|
32
33
|
|
|
@@ -53,12 +54,6 @@ The contents looks like this (all properties are optional):
|
|
|
53
54
|
|
|
54
55
|
When passing a server name, `tct` will look for a full match with a name or a partial match (the start) with a domain.
|
|
55
56
|
|
|
56
|
-
### Repo
|
|
57
|
-
|
|
58
|
-
The `build` and `sql` commands make use of a configuration file in the repository named `tangelo-configuration-toolkit-repoconfig.json`. This contains information about the customer projects.
|
|
59
|
-
|
|
60
|
-
For a new repository, using `tct build --init` also creates the repoconfig-file. For existing projects not having the repoconfig-file, you can use `tct build --config` to generate it.
|
|
61
|
-
|
|
62
57
|
### oXygen
|
|
63
58
|
|
|
64
59
|
The `build -x` commands set projects transformation scenarios and masterfiles in the oXygen project file with the following functionality:
|
package/index.js
CHANGED
|
@@ -8,6 +8,7 @@ String.prototype.toFws = function(){
|
|
|
8
8
|
const {execSync} = require('child_process');
|
|
9
9
|
const findUp = require('find-up');
|
|
10
10
|
const fs = require('fs-extra');
|
|
11
|
+
const homedir = require('os').homedir();
|
|
11
12
|
const path = require('path');
|
|
12
13
|
|
|
13
14
|
const execGitCommand = require('./src/lib/exec-git-command');
|
|
@@ -45,17 +46,25 @@ global._perf = t1 => {
|
|
|
45
46
|
};
|
|
46
47
|
|
|
47
48
|
global._formatDate = date =>
|
|
48
|
-
date?.toLocaleDateString('en-gb', {day: 'numeric', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit'})
|
|
49
|
+
date?.toLocaleDateString('en-gb', {day: 'numeric', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit'})
|
|
49
50
|
;
|
|
50
51
|
|
|
52
|
+
|
|
53
|
+
global._packages = {
|
|
54
|
+
TCT: {name: '@tangelo/tangelo-configuration-toolkit', version: require('./package.json')?.version},
|
|
55
|
+
FDT: {name: '@fontoxml/fontoxml-development-tools'}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
|
|
51
59
|
global._paths = {
|
|
52
60
|
app: __dirname,
|
|
53
|
-
|
|
54
|
-
appconfig: findUp.sync(appname+'-appconfig.json'),
|
|
61
|
+
apphome: path.join(homedir, '.tct'),
|
|
55
62
|
repo: findUp.sync(dir => fs.existsSync(path.join(dir, '.git')) && dir, {type: 'directory'}) || '',
|
|
56
63
|
tdi: 'tangelo-default-implementation',
|
|
57
64
|
gitremote: 'git@bitbucket.org:tangelosoftware'
|
|
58
65
|
};
|
|
66
|
+
_paths.appdata = path.join(_paths.apphome, 'appdata.json');
|
|
67
|
+
_paths.appconfig = path.join(_paths.apphome, 'appconfig.json');
|
|
59
68
|
_paths.repoconfig = path.join(_paths.repo, appname+'-repoconfig.json');
|
|
60
69
|
_paths.apply = process.cwd().replace(_paths.repo, '').substr(1);
|
|
61
70
|
|
|
@@ -66,15 +75,37 @@ if (!_appdata.npmPath) {
|
|
|
66
75
|
_appdata._update({npmPath: execSync('npm config get prefix', {encoding: 'UTF-8'}).replace(/\s$/, '')});
|
|
67
76
|
}
|
|
68
77
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
78
|
+
|
|
79
|
+
if (!fs.existsSync(_paths.appconfig)) { // try to find old appconfig (TCT-162 => remove code block in next version)
|
|
80
|
+
fs.ensureDirSync(_paths.apphome);
|
|
81
|
+
const oldPathAppconfig = findUp.sync(appname+'-appconfig.json');
|
|
82
|
+
if (oldPathAppconfig) {
|
|
83
|
+
fs.renameSync(oldPathAppconfig, _paths.appconfig);
|
|
84
|
+
_info(`${appname}-appconfig.json moved to ${_paths.apphome}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
global._appconfig = { // default appconfig if file not found
|
|
89
|
+
'sharedConfigPath': path.join(homedir, 'Dropbox (Tangelo Software)/Product Distribution/tooling'),
|
|
90
|
+
'servers': [],
|
|
91
|
+
'defaultServer': 'tdpXX',
|
|
92
|
+
'defaultDatabase': 'tdpXX'
|
|
72
93
|
};
|
|
73
94
|
|
|
74
|
-
try {
|
|
75
|
-
|
|
95
|
+
try {
|
|
96
|
+
global._appconfig = fs.readJsonSync(_paths.appconfig);
|
|
97
|
+
}
|
|
98
|
+
catch({code, message}) {
|
|
99
|
+
if (code === 'ENOENT') { // create appconfig json if not exists
|
|
100
|
+
fs.ensureDirSync(_paths.apphome);
|
|
101
|
+
fs.writeJsonSync(_paths.appconfig, global._appconfig, {spaces: 2});
|
|
102
|
+
_info(`${_paths.appconfig} was created`);
|
|
103
|
+
}
|
|
104
|
+
else _error('Could not load app-config: '+message);
|
|
105
|
+
}
|
|
106
|
+
|
|
76
107
|
|
|
77
|
-
_appconfig.sharedConfigPath = path.resolve(_paths.appconfig
|
|
108
|
+
_appconfig.sharedConfigPath = path.resolve(_paths.appconfig, '..', _appconfig.sharedConfigPath || '', appname+'-appconfig.json');
|
|
78
109
|
_appconfig.shared = fs.readJsonSync(_appconfig.sharedConfigPath, {throws: false}) || {};
|
|
79
110
|
|
|
80
111
|
|
|
@@ -83,7 +114,8 @@ global._git = {
|
|
|
83
114
|
if (!_appdata.gitUser) _appdata._update({gitUser: execGitCommand(`config --get user.email`, _paths.repo)});
|
|
84
115
|
return _appdata.gitUser;
|
|
85
116
|
},
|
|
86
|
-
commitLocal () {
|
|
117
|
+
commitLocal (clearcache) {
|
|
118
|
+
if (clearcache) delete this.cache;
|
|
87
119
|
this.cache ??= execGitCommand(`log -1 --format=%D;%H;%cd --date=iso-strict`, _paths.repo, ['branch', 'hash', 'date']);
|
|
88
120
|
return this.cache;
|
|
89
121
|
},
|
|
@@ -92,7 +124,8 @@ global._git = {
|
|
|
92
124
|
return this.cache;
|
|
93
125
|
},
|
|
94
126
|
commitTdi: {
|
|
95
|
-
local () {
|
|
127
|
+
local (clearcache) {
|
|
128
|
+
if (clearcache) delete this.cache;
|
|
96
129
|
this.cache ??= execGitCommand(`log -1 --format=%D;%H;%cd --date=iso-strict`, path.join(_paths.repo, _paths.tdi), ['tags', 'hash', 'date']);
|
|
97
130
|
return this.cache;
|
|
98
131
|
},
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -8,13 +8,22 @@ module.exports = function cli () {
|
|
|
8
8
|
const txtTitle = 'Tangelo Configuration Toolkit'.bold.underline.cyan;
|
|
9
9
|
const txtVersion = `v${_packages.TCT.version}`.lblack;
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
yargs
|
|
12
12
|
.scriptName('tct')
|
|
13
13
|
.usage(`${txtTitle} ${txtVersion}\n\nUsage: $0 <command> [options]`)
|
|
14
14
|
.middleware(argv => { // executes before command handlers
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const command = argv._[0];
|
|
16
|
+
const optionsPassed = Object.keys(argv).length > 2;
|
|
17
|
+
const gitInitOrClone = (command === 'git' || command === 'g') && (argv.init || argv.clone);
|
|
18
|
+
|
|
19
|
+
if (!command && argv.config) {
|
|
20
|
+
_info(`Loaded appconfig:`);
|
|
21
|
+
_write(_paths.appconfig);
|
|
22
|
+
_write(_appconfig);
|
|
23
|
+
}
|
|
24
|
+
else if (optionsPassed && !gitInitOrClone) {
|
|
25
|
+
if (_tdiSubmoduleExists()) process.chdir(_paths.repo); // set cwd to repo root before executing an option
|
|
26
|
+
else _error('This option can only be used inside a git repo having the TDI submodule!');
|
|
18
27
|
}
|
|
19
28
|
})
|
|
20
29
|
.command({
|
|
@@ -121,21 +130,11 @@ module.exports = function cli () {
|
|
|
121
130
|
.check((argv, options) => {
|
|
122
131
|
const nonDefaultOptions = Object.keys(options.key).filter(o => !Object.keys(options.default).includes(o));
|
|
123
132
|
if (nonDefaultOptions.some(o => argv[o])) return true;
|
|
124
|
-
else throw new Error(
|
|
133
|
+
else throw new Error('Pass a non-default option');
|
|
125
134
|
})
|
|
126
135
|
.strict()
|
|
127
136
|
.wrap(100)
|
|
137
|
+
.parse()
|
|
128
138
|
;
|
|
129
139
|
|
|
130
|
-
|
|
131
|
-
if (!argv._[0]) { // no command chosen
|
|
132
|
-
|
|
133
|
-
if (argv.config) {
|
|
134
|
-
if (!_paths.appconfig) _error('No config loaded: tangelo-configuration-toolkit-appconfig.json not found');
|
|
135
|
-
_info(`Loaded appconfig (using ${_paths.appconfig}):`);
|
|
136
|
-
_write(_appconfig);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
|
|
141
140
|
};
|
|
@@ -29,17 +29,16 @@ const createSymlinks = () => {
|
|
|
29
29
|
|
|
30
30
|
module.exports = function build (argv) {
|
|
31
31
|
|
|
32
|
-
if (argv.init)
|
|
33
|
-
if (_isPre51()) _error('This option only works when using branch release/5.1 and up.');
|
|
32
|
+
if ((argv.init || argv.project) && _isPre51()) _error('This option only works when using branch release/5.1 and up.');
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (argv.project) {
|
|
39
|
-
if (_isPre51()) _error('This option only works when using branch release/5.1 and up.');
|
|
34
|
+
const predefinedAnswers = (argv.init === 'file' || argv.project === 'file') ? _appconfig.build : undefined;
|
|
35
|
+
// if not chosen to use predefined values by passing "file", erase the "build" property for old TDI commits
|
|
36
|
+
_appconfig.build = predefinedAnswers;
|
|
40
37
|
|
|
41
|
-
|
|
38
|
+
if (argv.init) _modulesTdi.require('build/init')(createSymlinks, predefinedAnswers);
|
|
42
39
|
|
|
40
|
+
if (argv.project === 'file') _modulesTdi.require('build/project').projectNew(createSymlinks, _repoconfig[0], predefinedAnswers);
|
|
41
|
+
else if (argv.project) {
|
|
43
42
|
inquirer
|
|
44
43
|
.prompt([{
|
|
45
44
|
message: 'Create project: ', name: 'project', type: 'list',
|
|
@@ -53,10 +52,8 @@ module.exports = function build (argv) {
|
|
|
53
52
|
]
|
|
54
53
|
}])
|
|
55
54
|
.then(a => {
|
|
56
|
-
if (a.project
|
|
57
|
-
else
|
|
58
|
-
projectCopy(createSymlinks, a.project);
|
|
59
|
-
}
|
|
55
|
+
if (a.project === 'TDI') _modulesTdi.require('build/project').projectNew(createSymlinks, _repoconfig[0]);
|
|
56
|
+
else _modulesTdi.require('build/project').projectCopy(createSymlinks, a.project);
|
|
60
57
|
});
|
|
61
58
|
}
|
|
62
59
|
|
|
@@ -76,7 +73,6 @@ module.exports = function build (argv) {
|
|
|
76
73
|
if (argv.config) {
|
|
77
74
|
if (_git.commitTdi.after(_git.commitTdi.stopUsingRepoconfigFile)) _error('This option only works for older repo\'s using a repoconfig file.');
|
|
78
75
|
|
|
79
|
-
|
|
80
76
|
inquirer
|
|
81
77
|
.prompt([{message: 'Be sure paths for projects are [customer]/[project]. Continue?', name: 'confirm', type: 'confirm'}])
|
|
82
78
|
.then(({confirm}) => {
|
|
@@ -19,8 +19,6 @@ module.exports = function fonto (argv) {
|
|
|
19
19
|
}
|
|
20
20
|
})();
|
|
21
21
|
|
|
22
|
-
if (!_tdiSubmoduleExists()) _error('TDI submodule folder is missing.');
|
|
23
|
-
|
|
24
22
|
// check if FDT is not installed globally, because then it won't be possible to use specific versions with npx
|
|
25
23
|
if (fs.pathExistsSync(path.join(_appdata.npmPath, 'node_modules', _packages.FDT.name))) {
|
|
26
24
|
_error(`A global installation of FDT has been found! Remove it first.\nExecute: npm r -g ${_packages.FDT.name}`);
|
package/src/modules/git/index.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
const {execSync, spawn} = require('child_process');
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const fs = require('fs-extra');
|
|
2
|
+
const inquirer = require('inquirer');
|
|
3
|
+
const path = require('path');
|
|
6
4
|
|
|
7
5
|
const execGitCommand = require('../../lib/exec-git-command');
|
|
8
6
|
const getTdiBranch = require('../../lib/get-tdi-branch');
|
|
@@ -15,7 +13,8 @@ const cmdExec = commands => new Promise(resolve => {
|
|
|
15
13
|
|
|
16
14
|
const log = msg => {
|
|
17
15
|
const line = msg.replace(/\s+$/, ''); // remove excessive whitespace
|
|
18
|
-
if (line)
|
|
16
|
+
if (line?.startsWith('fatal:')) _error(line);
|
|
17
|
+
else if (line) _write(line);
|
|
19
18
|
};
|
|
20
19
|
|
|
21
20
|
const cmdArr = command.split(/ (.+)/);
|
|
@@ -88,7 +87,7 @@ module.exports = function git (argv) {
|
|
|
88
87
|
}
|
|
89
88
|
|
|
90
89
|
if (argv.clone) {
|
|
91
|
-
if (argv.clone
|
|
90
|
+
if (typeof argv.clone !== 'string') _error('Pass a repository name!');
|
|
92
91
|
|
|
93
92
|
_info('Clone a client repository and do basic project initialization');
|
|
94
93
|
cmdExec([
|
|
@@ -96,8 +95,8 @@ module.exports = function git (argv) {
|
|
|
96
95
|
['git clone git@bitbucket.org:tangelosoftware/' + argv.clone + '.git']
|
|
97
96
|
])
|
|
98
97
|
.then(() => {
|
|
99
|
-
|
|
100
|
-
chdir('./' + argv.clone);
|
|
98
|
+
// Change directory for the next commands, it should have the same name as the clone argument from commandline at this point
|
|
99
|
+
process.chdir('./' + argv.clone);
|
|
101
100
|
cmdExec([
|
|
102
101
|
// Retrieve TDI submodule for this client
|
|
103
102
|
['git submodule update --init', 'Fetch submodules such as TDI'],
|
|
@@ -106,17 +105,9 @@ module.exports = function git (argv) {
|
|
|
106
105
|
// Create Oxygen project file and set name equal to repo name
|
|
107
106
|
[`tct b -x ${argv.clone}`, 'Create Oxygen project file'],
|
|
108
107
|
]);
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
_warn(`System environment variable 'GIT_SSH' is missing. (link to putty plink.exe)`);
|
|
113
|
-
}
|
|
114
|
-
if (!process.env.GIT_SSH_COMMAND) {
|
|
115
|
-
_warn(`System environment variable 'GIT_SSH_COMMAND' is missing. (link to putty plink.exe)`);
|
|
116
|
-
}
|
|
117
|
-
// continue display stack trace
|
|
118
|
-
throw e;
|
|
119
|
-
});
|
|
108
|
+
})
|
|
109
|
+
.catch(e => {throw e;})
|
|
110
|
+
;
|
|
120
111
|
}
|
|
121
112
|
|
|
122
113
|
if (argv.update) {
|
|
@@ -139,6 +130,9 @@ module.exports = function git (argv) {
|
|
|
139
130
|
const updateSubmoduleMsg = execGitCommand(`submodule update --remote`, _paths.repo);
|
|
140
131
|
if (updateSubmoduleMsg.error && !tdiFromDateCustom) _error(`Update submodule failed\n${updateSubmoduleMsg.error}`);
|
|
141
132
|
|
|
133
|
+
// update local TDI commit data
|
|
134
|
+
_git.commitTdi.local(true);
|
|
135
|
+
|
|
142
136
|
if (!tdiFromDateCustom) _info(`TDI submodule updated:\n${updateSubmoduleMsg}`);
|
|
143
137
|
|
|
144
138
|
// tdiMigrationFilePath should exist in latest commits of releases 5.3+; As we updated to the latest version this should work
|
|
@@ -162,6 +156,7 @@ module.exports = function git (argv) {
|
|
|
162
156
|
let relevantMigrationCount = 0;
|
|
163
157
|
// Apply callback for migrations
|
|
164
158
|
migrationsFiltered
|
|
159
|
+
.sort((a, b) => Date(a.releases[0].date)>Date(b.releases[0].date)?1:-1)
|
|
165
160
|
.forEach((m) => {
|
|
166
161
|
const date = _formatDate(new Date(m.releases.filter((r) => tdiBranch.name >= `release/${r.release}`)[0].date));
|
|
167
162
|
relevantMigrationCount += (m.callback(date, relevantMigrationCount+1)) === 1 ? 1 : 0;
|
|
@@ -195,13 +190,13 @@ module.exports = function git (argv) {
|
|
|
195
190
|
if (cmdPull.error) _warn(`Pull failed\n${cmdPull.error}`);
|
|
196
191
|
|
|
197
192
|
_info(`Checked out at commit:`);
|
|
198
|
-
const repoLog =
|
|
193
|
+
const repoLog = _git.commitLocal(true);
|
|
199
194
|
_write(`${_formatDate(repoLog.date)} - ${repoLog.tags} - ${repoLog.hash}`);
|
|
200
195
|
|
|
201
196
|
_info(`Retrieve submodules that belong to this repo-commit`); // update submodule recursively (set to version that belongs to repo)
|
|
202
197
|
_write(execGitCommand(`submodule update --recursive`, path.join(_paths.repo)));
|
|
203
198
|
_info(`Submodule checked out at commit:`);
|
|
204
|
-
const tdiLog =
|
|
199
|
+
const tdiLog = _git.commitTdi.local(true);
|
|
205
200
|
_write(`${_formatDate(tdiLog.date)} - ${tdiLog.tags} - ${tdiLog.hash}`);
|
|
206
201
|
const tdiBranch = getTdiBranch();
|
|
207
202
|
|