@tangelo/tangelo-configuration-toolkit 1.24.2 → 1.24.3
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 +94 -94
- package/Tangelo-Configuration-Toolkit.code-workspace +8 -0
- package/bin/index.js +2 -2
- package/package.json +1 -1
- package/src/cli.js +4 -1
- package/src/lib/get-tdi-branch.js +54 -45
- package/src/lib/gulp-batch-replace-with-filter.js +19 -19
- package/src/lib/gulp-simple-rename.js +11 -11
- package/src/modules/build/oxygen.js +177 -177
- package/src/modules/git/index.js +8 -10
- package/src/modules/info/index.js +201 -201
package/README.md
CHANGED
|
@@ -1,94 +1,94 @@
|
|
|
1
|
-
# tangelo-configuration-toolkit
|
|
2
|
-
|
|
3
|
-
Tangelo Configuration Toolkit is a command-line toolkit which offers support for developing a Tangelo configuration.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
The toolkit requires [NPM](https://www.npmjs.com/get-npm) on [Node.js®](https://nodejs.org/) (at least version 18.x). An active or maintenance LTS release is recommended. After installing Node.js, you can install the latest version of the Tangelo Configuration Toolkit globally on your system using the following command:
|
|
8
|
-
|
|
9
|
-
npm i -g @tangelo/tangelo-configuration-toolkit
|
|
10
|
-
|
|
11
|
-
## Usage
|
|
12
|
-
|
|
13
|
-
Get help for the available commands and see version:
|
|
14
|
-
|
|
15
|
-
tangelo-configuration-toolkit
|
|
16
|
-
|
|
17
|
-
Get help for a specific command, detailing all its arguments:
|
|
18
|
-
|
|
19
|
-
tangelo-configuration-toolkit <command>
|
|
20
|
-
|
|
21
|
-
Use the `tct` shorthand instead of `tangelo-configuration-toolkit`:
|
|
22
|
-
|
|
23
|
-
tct <command>
|
|
24
|
-
|
|
25
|
-
## Config
|
|
26
|
-
|
|
27
|
-
### Global
|
|
28
|
-
|
|
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.
|
|
31
|
-
|
|
32
|
-
The contents looks like this (all properties are optional):
|
|
33
|
-
|
|
34
|
-
{
|
|
35
|
-
"sharedConfigPath": "absolute/or/relative/path/to/folder/containing/shared/config",
|
|
36
|
-
"servers": [{
|
|
37
|
-
"config": {
|
|
38
|
-
"port": 22,
|
|
39
|
-
"parallel": 4,
|
|
40
|
-
"username": "username",
|
|
41
|
-
"remotedir": "/absolute/path/to/tangelo/config/folder/on/server"
|
|
42
|
-
},
|
|
43
|
-
"domains": ["domain.name.com"],
|
|
44
|
-
"name": "name-for-local-deploy"
|
|
45
|
-
}],
|
|
46
|
-
"serverDefaults": {
|
|
47
|
-
"config": {
|
|
48
|
-
...
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
"defaultServer": "can be set to the name of e.g. your favorite dev server",
|
|
52
|
-
"defaultDatabase": "can be set to the tnsname of e.g. your favorite dev server"
|
|
53
|
-
}
|
|
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.
|
|
56
|
-
|
|
57
|
-
### oXygen
|
|
58
|
-
|
|
59
|
-
The `build -x` commands set projects transformation scenarios and masterfiles in the oXygen project file with the following functionality:
|
|
60
|
-
- Will try to preserve manually added entries in the transformation scenarios and masterfiles
|
|
61
|
-
- Will remove non existing masterfiles or masterfiles that start with a '_'
|
|
62
|
-
- No masterfiles / scenarios will be added if their path match with oXygens hidden directory patterns
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
## Debug
|
|
66
|
-
|
|
67
|
-
Save this in the root of your local clone as `tct-dev.cmd`:
|
|
68
|
-
|
|
69
|
-
```
|
|
70
|
-
@ECHO off
|
|
71
|
-
SETLOCAL
|
|
72
|
-
CALL :find_dp0
|
|
73
|
-
|
|
74
|
-
IF EXIST "%dp0%\node.exe" (
|
|
75
|
-
SET "_prog=%dp0%\node.exe"
|
|
76
|
-
) ELSE (
|
|
77
|
-
SET "_prog=node"
|
|
78
|
-
SET PATHEXT=%PATHEXT:;.JS;=;%
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
"%_prog%" "%dp0%\index.js" %*
|
|
82
|
-
ENDLOCAL
|
|
83
|
-
EXIT /b %errorlevel%
|
|
84
|
-
:find_dp0
|
|
85
|
-
SET dp0=%~dp0
|
|
86
|
-
EXIT /b
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
Then:
|
|
90
|
-
|
|
91
|
-
- open a 'Javascript Debug Terminal' in VSCode
|
|
92
|
-
- jump to a customer folder ( you can use `tan-cust` for this)
|
|
93
|
-
- set a breakpoint
|
|
94
|
-
- type (for instance): `tct-dev d -c`
|
|
1
|
+
# tangelo-configuration-toolkit
|
|
2
|
+
|
|
3
|
+
Tangelo Configuration Toolkit is a command-line toolkit which offers support for developing a Tangelo configuration.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
The toolkit requires [NPM](https://www.npmjs.com/get-npm) on [Node.js®](https://nodejs.org/) (at least version 18.x). An active or maintenance LTS release is recommended. After installing Node.js, you can install the latest version of the Tangelo Configuration Toolkit globally on your system using the following command:
|
|
8
|
+
|
|
9
|
+
npm i -g @tangelo/tangelo-configuration-toolkit
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
Get help for the available commands and see version:
|
|
14
|
+
|
|
15
|
+
tangelo-configuration-toolkit
|
|
16
|
+
|
|
17
|
+
Get help for a specific command, detailing all its arguments:
|
|
18
|
+
|
|
19
|
+
tangelo-configuration-toolkit <command>
|
|
20
|
+
|
|
21
|
+
Use the `tct` shorthand instead of `tangelo-configuration-toolkit`:
|
|
22
|
+
|
|
23
|
+
tct <command>
|
|
24
|
+
|
|
25
|
+
## Config
|
|
26
|
+
|
|
27
|
+
### Global
|
|
28
|
+
|
|
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.
|
|
31
|
+
|
|
32
|
+
The contents looks like this (all properties are optional):
|
|
33
|
+
|
|
34
|
+
{
|
|
35
|
+
"sharedConfigPath": "absolute/or/relative/path/to/folder/containing/shared/config",
|
|
36
|
+
"servers": [{
|
|
37
|
+
"config": {
|
|
38
|
+
"port": 22,
|
|
39
|
+
"parallel": 4,
|
|
40
|
+
"username": "username",
|
|
41
|
+
"remotedir": "/absolute/path/to/tangelo/config/folder/on/server"
|
|
42
|
+
},
|
|
43
|
+
"domains": ["domain.name.com"],
|
|
44
|
+
"name": "name-for-local-deploy"
|
|
45
|
+
}],
|
|
46
|
+
"serverDefaults": {
|
|
47
|
+
"config": {
|
|
48
|
+
...
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
"defaultServer": "can be set to the name of e.g. your favorite dev server",
|
|
52
|
+
"defaultDatabase": "can be set to the tnsname of e.g. your favorite dev server"
|
|
53
|
+
}
|
|
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.
|
|
56
|
+
|
|
57
|
+
### oXygen
|
|
58
|
+
|
|
59
|
+
The `build -x` commands set projects transformation scenarios and masterfiles in the oXygen project file with the following functionality:
|
|
60
|
+
- Will try to preserve manually added entries in the transformation scenarios and masterfiles
|
|
61
|
+
- Will remove non existing masterfiles or masterfiles that start with a '_'
|
|
62
|
+
- No masterfiles / scenarios will be added if their path match with oXygens hidden directory patterns
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
## Debug
|
|
66
|
+
|
|
67
|
+
Save this in the root of your local clone as `tct-dev.cmd`:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
@ECHO off
|
|
71
|
+
SETLOCAL
|
|
72
|
+
CALL :find_dp0
|
|
73
|
+
|
|
74
|
+
IF EXIST "%dp0%\node.exe" (
|
|
75
|
+
SET "_prog=%dp0%\node.exe"
|
|
76
|
+
) ELSE (
|
|
77
|
+
SET "_prog=node"
|
|
78
|
+
SET PATHEXT=%PATHEXT:;.JS;=;%
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
"%_prog%" "%dp0%\index.js" %*
|
|
82
|
+
ENDLOCAL
|
|
83
|
+
EXIT /b %errorlevel%
|
|
84
|
+
:find_dp0
|
|
85
|
+
SET dp0=%~dp0
|
|
86
|
+
EXIT /b
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Then:
|
|
90
|
+
|
|
91
|
+
- open a 'Javascript Debug Terminal' in VSCode
|
|
92
|
+
- jump to a customer folder ( you can use `tan-cust` for this)
|
|
93
|
+
- set a breakpoint
|
|
94
|
+
- type (for instance): `tct-dev d -c`
|
package/bin/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
3
|
require('..');
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -77,7 +77,10 @@ module.exports = function cli () {
|
|
|
77
77
|
reset: {alias: 'r', desc: 'Reset repository to last commit', conflicts: ['i', 'c', 'u']},
|
|
78
78
|
clone: {alias: 'c', desc: 'Clone a client repository and do basic setup', conflicts: ['i', 'r', 'u']},
|
|
79
79
|
'update-repo': {alias: 'ur', desc: 'Update repository', conflicts: ['i', 'r', 'c']},
|
|
80
|
-
'update-submodule': {alias: 'us', desc: 'Update TDI submodule, optionally pass release branch (without "release/")', conflicts: ['i', 'r', 'c']
|
|
80
|
+
'update-submodule': {alias: 'us', desc: 'Update TDI submodule, optionally pass release branch (without "release/")', conflicts: ['i', 'r', 'c'], type:"string",
|
|
81
|
+
// Running --us with no argument should default to true - defaulting to empty string throws a yargs error
|
|
82
|
+
coerce: (v => v || true)
|
|
83
|
+
},
|
|
81
84
|
dates: {alias: 'd', desc: '[hidden] Use i.c.w. update-submodule, pass 2 dates in format yyyy-mm-dd', conflicts: ['i', 'r', 'c'], implies: 'update-submodule', requiresArg: true, array: true, hidden: !_devmode}
|
|
82
85
|
},
|
|
83
86
|
handler: require('./modules/git')
|
|
@@ -1,46 +1,55 @@
|
|
|
1
|
-
const execGitCommand = require('./exec-git-command');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
// Fetch all
|
|
9
|
-
_info(`Fetch TDI submodule`);
|
|
10
|
-
const cmdFetch = execGitCommand('fetch -pf --all', tdiPath);
|
|
11
|
-
if (cmdFetch.error) _warn(`Fetch failed\n${cmdFetch.error}`);
|
|
12
|
-
|
|
13
|
-
let toBranch;
|
|
14
|
-
if (toBranchName) {
|
|
15
|
-
// Check if specified branch exists; we will update to this branch
|
|
16
|
-
toBranch = String(toBranchName).replace(/(?:release\/)?(\d+(?:\.[\dxt]+)*)/, `release/$1`);
|
|
17
|
-
const branchExists = execGitCommand(`branch --remote`, tdiPath).match(`origin/${toBranch}`);
|
|
18
|
-
if (!branchExists) _error(`TDI branch "${toBranch}" does not exist. Note that TCT can only update to a release branch.`);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Get remote release branches containing TDI HEAD commit
|
|
22
|
-
const releaseBranches = execGitCommand(`branch --all --contains ${_git.commitTdi.local().hash}`, tdiPath).match(/remotes\/origin\/release\/[^\s]+/gsm);
|
|
23
|
-
if (!releaseBranches || releaseBranches.error) _error(`Could not retrieve TDI release branches`);
|
|
24
|
-
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
1
|
+
const execGitCommand = require('./exec-git-command');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const compareVersions = require('compare-versions');
|
|
4
|
+
|
|
5
|
+
module.exports = function getTdiBranch(toBranchName) {
|
|
6
|
+
const tdiPath = path.join(_paths.repo, _paths.tdi);
|
|
7
|
+
|
|
8
|
+
// Fetch all
|
|
9
|
+
_info(`Fetch TDI submodule`);
|
|
10
|
+
const cmdFetch = execGitCommand('fetch -pf --all', tdiPath);
|
|
11
|
+
if (cmdFetch.error) _warn(`Fetch failed\n${cmdFetch.error}`);
|
|
12
|
+
|
|
13
|
+
let toBranch;
|
|
14
|
+
if (toBranchName) {
|
|
15
|
+
// Check if specified branch exists; we will update to this branch
|
|
16
|
+
toBranch = String(toBranchName).replace(/(?:release\/)?(\d+(?:\.[\dxt]+)*)/, `release/$1`);
|
|
17
|
+
const branchExists = execGitCommand(`branch --remote`, tdiPath).match(`origin/${toBranch}`);
|
|
18
|
+
if (!branchExists) _error(`TDI branch "${toBranch}" does not exist. Note that TCT can only update to a release branch.`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Get remote release branches containing TDI HEAD commit
|
|
22
|
+
const releaseBranches = execGitCommand(`branch --all --contains ${_git.commitTdi.local().hash}`, tdiPath).match(/remotes\/origin\/release\/[^\s]+/gsm);
|
|
23
|
+
if (!releaseBranches || releaseBranches.error) _error(`Could not retrieve TDI release branches`);
|
|
24
|
+
|
|
25
|
+
// Create a sorted list of release branches with their versions:
|
|
26
|
+
const sortedBranches = releaseBranches
|
|
27
|
+
.map(branch => {
|
|
28
|
+
return {
|
|
29
|
+
name: branch.replace('remotes/origin/', ''),
|
|
30
|
+
version: branch.replace('remotes/origin/release/', '')
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
.sort((a, b) => compareVersions(a.version, b.version));
|
|
34
|
+
|
|
35
|
+
// Choose the first possible branch; prefer release/5.1 over release/5.2:
|
|
36
|
+
const tdiBranch = sortedBranches[0];
|
|
37
|
+
|
|
38
|
+
// In case of branch switch set from.name to the old branch and name to the new branch
|
|
39
|
+
if (toBranch) {
|
|
40
|
+
const toVersion = toBranch?.replace('release/', '');
|
|
41
|
+
if (compareVersions.compare(tdiBranch.version, toVersion, '>')) _error(`You cannot downgrade to a lower release branch with TCT.`);
|
|
42
|
+
tdiBranch.from = {name: tdiBranch.name, version: tdiBranch.version};
|
|
43
|
+
tdiBranch.name = toBranch;
|
|
44
|
+
tdiBranch.version = toVersion;
|
|
45
|
+
|
|
46
|
+
const branchHash = execGitCommand(`rev-parse origin/${toBranch}`, tdiPath);
|
|
47
|
+
const commonAncestorHash = execGitCommand(`merge-base ${_git.commitTdi.local().hash} ${branchHash}`, tdiPath);
|
|
48
|
+
const commonAncestorDate = execGitCommand(`show ${commonAncestorHash} --no-patch --format=%cd --date=iso-strict `, tdiPath, ['date']).date;
|
|
49
|
+
tdiBranch.commonAncestor = {date: new Date(commonAncestorDate)};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Get number of commits behind
|
|
53
|
+
tdiBranch.commitsBehind = execGitCommand(`rev-list HEAD...origin/${tdiBranch.name} --count`, tdiPath);
|
|
54
|
+
return tdiBranch;
|
|
46
55
|
};
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
// based on gulp-batch-replace
|
|
2
|
-
|
|
3
|
-
const es = require('event-stream'), minimatch = require('minimatch'), istextorbinary = require('istextorbinary');
|
|
4
|
-
|
|
5
|
-
const execReplace = (c, s, r) => Buffer.from(s instanceof RegExp ? String(c).replace(s, r) : String(c).split(s).join(r));
|
|
6
|
-
|
|
7
|
-
module.exports = arr => {
|
|
8
|
-
return es.map((file, callback) => {
|
|
9
|
-
if(file.contents instanceof Buffer) {
|
|
10
|
-
for (const e of arr) {
|
|
11
|
-
// exec if no glob is passed or if glob matches, and it's a text file
|
|
12
|
-
if ((!e[2] || minimatch(file.path, e[2])) && istextorbinary.isText(file.path, file)) {
|
|
13
|
-
file.contents = execReplace(file.contents, e[0], e[1]);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
callback(null, file);
|
|
18
|
-
});
|
|
19
|
-
};
|
|
1
|
+
// based on gulp-batch-replace
|
|
2
|
+
|
|
3
|
+
const es = require('event-stream'), minimatch = require('minimatch'), istextorbinary = require('istextorbinary');
|
|
4
|
+
|
|
5
|
+
const execReplace = (c, s, r) => Buffer.from(s instanceof RegExp ? String(c).replace(s, r) : String(c).split(s).join(r));
|
|
6
|
+
|
|
7
|
+
module.exports = arr => {
|
|
8
|
+
return es.map((file, callback) => {
|
|
9
|
+
if(file.contents instanceof Buffer) {
|
|
10
|
+
for (const e of arr) {
|
|
11
|
+
// exec if no glob is passed or if glob matches, and it's a text file
|
|
12
|
+
if ((!e[2] || minimatch(file.path, e[2])) && istextorbinary.isText(file.path, file)) {
|
|
13
|
+
file.contents = execReplace(file.contents, e[0], e[1]);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
callback(null, file);
|
|
18
|
+
});
|
|
19
|
+
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
// replacement for the official (but deprecated) gulp-simple-rename
|
|
2
|
-
// kept same name because of usage in tdi
|
|
3
|
-
|
|
4
|
-
const through2 = require('through2');
|
|
5
|
-
|
|
6
|
-
module.exports = (fn) => {
|
|
7
|
-
return through2.obj((file, enc, cb) => {
|
|
8
|
-
file.path = fn(file.path);
|
|
9
|
-
cb(null, file);
|
|
10
|
-
});
|
|
11
|
-
};
|
|
1
|
+
// replacement for the official (but deprecated) gulp-simple-rename
|
|
2
|
+
// kept same name because of usage in tdi
|
|
3
|
+
|
|
4
|
+
const through2 = require('through2');
|
|
5
|
+
|
|
6
|
+
module.exports = (fn) => {
|
|
7
|
+
return through2.obj((file, enc, cb) => {
|
|
8
|
+
file.path = fn(file.path);
|
|
9
|
+
cb(null, file);
|
|
10
|
+
});
|
|
11
|
+
};
|
|
@@ -1,178 +1,178 @@
|
|
|
1
|
-
const fs = require('fs-extra');
|
|
2
|
-
const globby = require('globby');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const SaxonJS = require('saxon-js');
|
|
5
|
-
|
|
6
|
-
const spConfigPath = 'build/oxygen/stylesheetPaths.json';
|
|
7
|
-
const sefFilePath = 'build/oxygen/createProjectFile.sef.json';
|
|
8
|
-
const cmscustomPath = 'config/cmscustom/';
|
|
9
|
-
const siteStylesheetsPath = 'config/txp/site-stylesheets/';
|
|
10
|
-
|
|
11
|
-
const masterFiles = new Set;
|
|
12
|
-
const transformationScenarios = [];
|
|
13
|
-
|
|
14
|
-
let spConfig, sefFile;
|
|
15
|
-
|
|
16
|
-
const convertToValidFilename = string => string.replace(/[/|\\:*?"<>]/g, ' ');
|
|
17
|
-
|
|
18
|
-
const createProjectFile = (config, newXprFile) => {
|
|
19
|
-
_info('Initializing xpr file(s):');
|
|
20
|
-
const xprFiles = [...globby.sync(`*.xpr`)];
|
|
21
|
-
// Add newXprFile at the start of xprFiles if it does not already exists:
|
|
22
|
-
if (newXprFile && xprFiles.indexOf(newXprFile)===-1) xprFiles.unshift(newXprFile);
|
|
23
|
-
|
|
24
|
-
// Copy xpr file from TDI if it does not exists yet;
|
|
25
|
-
if (xprFiles[0] && !newXprFile) _write(`Found: ${xprFiles.join(', ')}`);
|
|
26
|
-
else {
|
|
27
|
-
if (!newXprFile) {
|
|
28
|
-
// Set xpr filename to customer name (assumes correct upsert scripts structure)
|
|
29
|
-
const customers = new Set;
|
|
30
|
-
_repoconfig.forEach(p => customers.add(p.customer_name));
|
|
31
|
-
xprFiles.push(convertToValidFilename([...customers].join(' - ')) + '.xpr');
|
|
32
|
-
}
|
|
33
|
-
// Copy new xpr file
|
|
34
|
-
fs.copySync(path.join(_paths.repo, 'tangelo-default-implementation/src/[customer].xpr'), path.join(_paths.repo, xprFiles[0]));
|
|
35
|
-
_write(`Created: '${xprFiles[0]}'`);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Search for transformationScenarios/masterfiles based on TDI submodule oxygenProjectFile config
|
|
39
|
-
_info('\nSearching for transformationScenarios/masterfiles');
|
|
40
|
-
config.oxygenProjectFile.forEach(
|
|
41
|
-
pf => {
|
|
42
|
-
// Collect transformation scenarios and add them to the transformationScenarios array; add individual stylesheets to the masterFiles set.
|
|
43
|
-
if (pf.transformation) getTransformations(pf.transformation);
|
|
44
|
-
// Add files to the masterfiles set.
|
|
45
|
-
else if (pf.masterfile) getMasterfiles(pf.masterfile);
|
|
46
|
-
}
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
// update all .xpr files with collected transformation scenarios and masterfiles.
|
|
50
|
-
transformXprFile(xprFiles);
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const getTransformations = config => {
|
|
54
|
-
_repoconfig.forEach(rc => {
|
|
55
|
-
// get pathname of customer/project
|
|
56
|
-
const [customerPath, projectPath] = config.location === 'database' ? rc.path_dbconfig : rc.path_cmscustom;
|
|
57
|
-
|
|
58
|
-
// set pathname of customer/project in location glob-expression
|
|
59
|
-
const location = path.join(
|
|
60
|
-
_paths.repo,
|
|
61
|
-
config.files.replace(/\[customer\]/, customerPath).replace(/\[project\]/, projectPath)
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
globby
|
|
65
|
-
.sync(`${location}`)
|
|
66
|
-
.forEach(f => {
|
|
67
|
-
// extract baseStrings from file
|
|
68
|
-
const fileString = fs.readFileSync(f).toString();
|
|
69
|
-
const baseStrings = fileString.match(RegExp(config.extracts.base, 'gm'));
|
|
70
|
-
|
|
71
|
-
if (fileString.replace(/\s|^prompt\s.*$/gm, '') !== '') {
|
|
72
|
-
if (baseStrings) {
|
|
73
|
-
baseStrings.forEach(s => {
|
|
74
|
-
// extract type, name, files info from baseString
|
|
75
|
-
const type = config.extracts.type ? s.match(RegExp(config.extracts.type))[1] : config.values.type;
|
|
76
|
-
const name = config.extracts.name ? s.match(RegExp(config.extracts.name))[1] : config.values.name;
|
|
77
|
-
const files = s.match(RegExp(config.extracts.files))[1];
|
|
78
|
-
|
|
79
|
-
// Add transformation scenario to the transformationScenario array
|
|
80
|
-
transformationScenarios.push({
|
|
81
|
-
name: `${type}: ${name} (${rc.customer_name}, ${rc.project_name})`, // note that in createProjectFile.xsl a regex is added that matches scenarios based on this name. This to preserve manually added scenarios.
|
|
82
|
-
transformationScenario: files,
|
|
83
|
-
location: config.location === 'txp' ? siteStylesheetsPath : cmscustomPath
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
// Add each non-tdi stylesheet in transformation scenario to the masterFiles set
|
|
87
|
-
files.split(',').forEach(f => {
|
|
88
|
-
const filePath = `${config.location === 'txp' ? siteStylesheetsPath : cmscustomPath}${f}`;
|
|
89
|
-
if (!f.startsWith('tdi')) masterFiles.add(filePath);
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
} else {
|
|
93
|
-
_write(`No transformation scenarios found in ${f} for '${config.extracts.base}'`);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const getMasterfiles = config => {
|
|
103
|
-
globby
|
|
104
|
-
.sync(`${path.join(_paths.repo, config.files)}`)
|
|
105
|
-
.forEach(cf => {
|
|
106
|
-
// Check if masterfile should be extracted from file
|
|
107
|
-
const fileString = fs.readFileSync(cf).toString();
|
|
108
|
-
if (fileString.replace(/\s|^prompt\s.*$/gm, '')!=='') {
|
|
109
|
-
if (config.extracts) {
|
|
110
|
-
// extract baseStrings from file
|
|
111
|
-
const baseStrings = fileString.match(RegExp(config.extracts.base, 'gm'));
|
|
112
|
-
|
|
113
|
-
if (baseStrings) {
|
|
114
|
-
baseStrings.forEach(s => {
|
|
115
|
-
// extract (comma-separated) list of masterfiles
|
|
116
|
-
const filesString = s.match(RegExp(config.extracts.files))[1];
|
|
117
|
-
if (!filesString) _error(`No masterfiles found in '${s}' for '${config.extracts.files}'`);
|
|
118
|
-
|
|
119
|
-
// Add each non-tdi masterfile to the masterFiles set
|
|
120
|
-
filesString.split(',').forEach(f => {
|
|
121
|
-
if (!f.startsWith('tdi')){
|
|
122
|
-
const filePath = `${config.location === 'txp' ? siteStylesheetsPath : cmscustomPath}${f}`;
|
|
123
|
-
masterFiles.add(filePath);
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
} else {
|
|
128
|
-
_write(`No masterfiles found in ${cf} for '${config.extracts.base}'`);
|
|
129
|
-
}
|
|
130
|
-
} else { // Add synced file to masterfiles; strip path from c:/... hence it starts with config/cmscustom or config/txp/site-stylesheets
|
|
131
|
-
const filePath = config.location === 'txp' ? `${siteStylesheetsPath}${cf.split(siteStylesheetsPath)[1]}` : `${cmscustomPath}${cf.split(cmscustomPath)[1]}`;
|
|
132
|
-
masterFiles.add(filePath);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
const transformXprFile = xprFiles => {
|
|
140
|
-
_info('\nUpdating xpr file(s):');
|
|
141
|
-
// create with: xslt3 -t -xsl:createProjectFile.xsl -export:createProjectFile.sef.json v -nogo'
|
|
142
|
-
|
|
143
|
-
xprFiles
|
|
144
|
-
.forEach(xprFile => {
|
|
145
|
-
// Transform xpr; add masterfiles and transformationScenarios as parameters of the stylesheet
|
|
146
|
-
_write(`${xprFile}\n`);
|
|
147
|
-
SaxonJS.transform({
|
|
148
|
-
stylesheetText: JSON.stringify(sefFile),
|
|
149
|
-
stylesheetBaseURI: 'createProjectFile.sef.json',
|
|
150
|
-
sourceFileName: path.join(_paths.repo, xprFile),
|
|
151
|
-
destination: 'serialized',
|
|
152
|
-
stylesheetParams: {
|
|
153
|
-
'masterfiles': [...masterFiles],
|
|
154
|
-
'Q{}transformationScenarios': transformationScenarios
|
|
155
|
-
}
|
|
156
|
-
}, 'async')
|
|
157
|
-
.then(output => {
|
|
158
|
-
// Write result of transformation to xpr file
|
|
159
|
-
fs.writeFileSync(path.join(_paths.repo, xprFile), output.principalResult);
|
|
160
|
-
})
|
|
161
|
-
.catch(e => _warn(`Failed to update: ${xprFile}\n ${e}`));
|
|
162
|
-
});
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
module.exports = function oxygen (arg) {
|
|
167
|
-
// Set projects transformation scenarios and masterfiles in oXygen project file
|
|
168
|
-
// - Will try to preserve manually added entries in the transformation scenarios and masterfiles
|
|
169
|
-
// - Will remove non existing masterfiles or masterfiles that start with a '_'
|
|
170
|
-
|
|
171
|
-
spConfig = _modulesTdi.require(spConfigPath);
|
|
172
|
-
sefFile = _modulesTdi.require(sefFilePath);
|
|
173
|
-
|
|
174
|
-
if (!spConfig || !sefFile) _error(`Cannot find required files in TDI submodule. Try updating TDI submodule.`);
|
|
175
|
-
|
|
176
|
-
const newXprFile = (typeof arg === 'string') ? convertToValidFilename(arg) + '.xpr' : null;
|
|
177
|
-
createProjectFile(spConfig, newXprFile);
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const globby = require('globby');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const SaxonJS = require('saxon-js');
|
|
5
|
+
|
|
6
|
+
const spConfigPath = 'build/oxygen/stylesheetPaths.json';
|
|
7
|
+
const sefFilePath = 'build/oxygen/createProjectFile.sef.json';
|
|
8
|
+
const cmscustomPath = 'config/cmscustom/';
|
|
9
|
+
const siteStylesheetsPath = 'config/txp/site-stylesheets/';
|
|
10
|
+
|
|
11
|
+
const masterFiles = new Set;
|
|
12
|
+
const transformationScenarios = [];
|
|
13
|
+
|
|
14
|
+
let spConfig, sefFile;
|
|
15
|
+
|
|
16
|
+
const convertToValidFilename = string => string.replace(/[/|\\:*?"<>]/g, ' ');
|
|
17
|
+
|
|
18
|
+
const createProjectFile = (config, newXprFile) => {
|
|
19
|
+
_info('Initializing xpr file(s):');
|
|
20
|
+
const xprFiles = [...globby.sync(`*.xpr`)];
|
|
21
|
+
// Add newXprFile at the start of xprFiles if it does not already exists:
|
|
22
|
+
if (newXprFile && xprFiles.indexOf(newXprFile)===-1) xprFiles.unshift(newXprFile);
|
|
23
|
+
|
|
24
|
+
// Copy xpr file from TDI if it does not exists yet;
|
|
25
|
+
if (xprFiles[0] && !newXprFile) _write(`Found: ${xprFiles.join(', ')}`);
|
|
26
|
+
else {
|
|
27
|
+
if (!newXprFile) {
|
|
28
|
+
// Set xpr filename to customer name (assumes correct upsert scripts structure)
|
|
29
|
+
const customers = new Set;
|
|
30
|
+
_repoconfig.forEach(p => customers.add(p.customer_name));
|
|
31
|
+
xprFiles.push(convertToValidFilename([...customers].join(' - ')) + '.xpr');
|
|
32
|
+
}
|
|
33
|
+
// Copy new xpr file
|
|
34
|
+
fs.copySync(path.join(_paths.repo, 'tangelo-default-implementation/src/[customer].xpr'), path.join(_paths.repo, xprFiles[0]));
|
|
35
|
+
_write(`Created: '${xprFiles[0]}'`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Search for transformationScenarios/masterfiles based on TDI submodule oxygenProjectFile config
|
|
39
|
+
_info('\nSearching for transformationScenarios/masterfiles');
|
|
40
|
+
config.oxygenProjectFile.forEach(
|
|
41
|
+
pf => {
|
|
42
|
+
// Collect transformation scenarios and add them to the transformationScenarios array; add individual stylesheets to the masterFiles set.
|
|
43
|
+
if (pf.transformation) getTransformations(pf.transformation);
|
|
44
|
+
// Add files to the masterfiles set.
|
|
45
|
+
else if (pf.masterfile) getMasterfiles(pf.masterfile);
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
// update all .xpr files with collected transformation scenarios and masterfiles.
|
|
50
|
+
transformXprFile(xprFiles);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const getTransformations = config => {
|
|
54
|
+
_repoconfig.forEach(rc => {
|
|
55
|
+
// get pathname of customer/project
|
|
56
|
+
const [customerPath, projectPath] = config.location === 'database' ? rc.path_dbconfig : rc.path_cmscustom;
|
|
57
|
+
|
|
58
|
+
// set pathname of customer/project in location glob-expression
|
|
59
|
+
const location = path.join(
|
|
60
|
+
_paths.repo,
|
|
61
|
+
config.files.replace(/\[customer\]/, customerPath).replace(/\[project\]/, projectPath)
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
globby
|
|
65
|
+
.sync(`${location}`)
|
|
66
|
+
.forEach(f => {
|
|
67
|
+
// extract baseStrings from file
|
|
68
|
+
const fileString = fs.readFileSync(f).toString();
|
|
69
|
+
const baseStrings = fileString.match(RegExp(config.extracts.base, 'gm'));
|
|
70
|
+
|
|
71
|
+
if (fileString.replace(/\s|^prompt\s.*$/gm, '') !== '') {
|
|
72
|
+
if (baseStrings) {
|
|
73
|
+
baseStrings.forEach(s => {
|
|
74
|
+
// extract type, name, files info from baseString
|
|
75
|
+
const type = config.extracts.type ? s.match(RegExp(config.extracts.type))[1] : config.values.type;
|
|
76
|
+
const name = config.extracts.name ? s.match(RegExp(config.extracts.name))[1] : config.values.name;
|
|
77
|
+
const files = s.match(RegExp(config.extracts.files))[1];
|
|
78
|
+
|
|
79
|
+
// Add transformation scenario to the transformationScenario array
|
|
80
|
+
transformationScenarios.push({
|
|
81
|
+
name: `${type}: ${name} (${rc.customer_name}, ${rc.project_name})`, // note that in createProjectFile.xsl a regex is added that matches scenarios based on this name. This to preserve manually added scenarios.
|
|
82
|
+
transformationScenario: files,
|
|
83
|
+
location: config.location === 'txp' ? siteStylesheetsPath : cmscustomPath
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Add each non-tdi stylesheet in transformation scenario to the masterFiles set
|
|
87
|
+
files.split(',').forEach(f => {
|
|
88
|
+
const filePath = `${config.location === 'txp' ? siteStylesheetsPath : cmscustomPath}${f}`;
|
|
89
|
+
if (!f.startsWith('tdi')) masterFiles.add(filePath);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
} else {
|
|
93
|
+
_write(`No transformation scenarios found in ${f} for '${config.extracts.base}'`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
const getMasterfiles = config => {
|
|
103
|
+
globby
|
|
104
|
+
.sync(`${path.join(_paths.repo, config.files)}`)
|
|
105
|
+
.forEach(cf => {
|
|
106
|
+
// Check if masterfile should be extracted from file
|
|
107
|
+
const fileString = fs.readFileSync(cf).toString();
|
|
108
|
+
if (fileString.replace(/\s|^prompt\s.*$/gm, '')!=='') {
|
|
109
|
+
if (config.extracts) {
|
|
110
|
+
// extract baseStrings from file
|
|
111
|
+
const baseStrings = fileString.match(RegExp(config.extracts.base, 'gm'));
|
|
112
|
+
|
|
113
|
+
if (baseStrings) {
|
|
114
|
+
baseStrings.forEach(s => {
|
|
115
|
+
// extract (comma-separated) list of masterfiles
|
|
116
|
+
const filesString = s.match(RegExp(config.extracts.files))[1];
|
|
117
|
+
if (!filesString) _error(`No masterfiles found in '${s}' for '${config.extracts.files}'`);
|
|
118
|
+
|
|
119
|
+
// Add each non-tdi masterfile to the masterFiles set
|
|
120
|
+
filesString.split(',').forEach(f => {
|
|
121
|
+
if (!f.startsWith('tdi')){
|
|
122
|
+
const filePath = `${config.location === 'txp' ? siteStylesheetsPath : cmscustomPath}${f}`;
|
|
123
|
+
masterFiles.add(filePath);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
} else {
|
|
128
|
+
_write(`No masterfiles found in ${cf} for '${config.extracts.base}'`);
|
|
129
|
+
}
|
|
130
|
+
} else { // Add synced file to masterfiles; strip path from c:/... hence it starts with config/cmscustom or config/txp/site-stylesheets
|
|
131
|
+
const filePath = config.location === 'txp' ? `${siteStylesheetsPath}${cf.split(siteStylesheetsPath)[1]}` : `${cmscustomPath}${cf.split(cmscustomPath)[1]}`;
|
|
132
|
+
masterFiles.add(filePath);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const transformXprFile = xprFiles => {
|
|
140
|
+
_info('\nUpdating xpr file(s):');
|
|
141
|
+
// create with: xslt3 -t -xsl:createProjectFile.xsl -export:createProjectFile.sef.json v -nogo'
|
|
142
|
+
|
|
143
|
+
xprFiles
|
|
144
|
+
.forEach(xprFile => {
|
|
145
|
+
// Transform xpr; add masterfiles and transformationScenarios as parameters of the stylesheet
|
|
146
|
+
_write(`${xprFile}\n`);
|
|
147
|
+
SaxonJS.transform({
|
|
148
|
+
stylesheetText: JSON.stringify(sefFile),
|
|
149
|
+
stylesheetBaseURI: 'createProjectFile.sef.json',
|
|
150
|
+
sourceFileName: path.join(_paths.repo, xprFile),
|
|
151
|
+
destination: 'serialized',
|
|
152
|
+
stylesheetParams: {
|
|
153
|
+
'masterfiles': [...masterFiles],
|
|
154
|
+
'Q{}transformationScenarios': transformationScenarios
|
|
155
|
+
}
|
|
156
|
+
}, 'async')
|
|
157
|
+
.then(output => {
|
|
158
|
+
// Write result of transformation to xpr file
|
|
159
|
+
fs.writeFileSync(path.join(_paths.repo, xprFile), output.principalResult);
|
|
160
|
+
})
|
|
161
|
+
.catch(e => _warn(`Failed to update: ${xprFile}\n ${e}`));
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
module.exports = function oxygen (arg) {
|
|
167
|
+
// Set projects transformation scenarios and masterfiles in oXygen project file
|
|
168
|
+
// - Will try to preserve manually added entries in the transformation scenarios and masterfiles
|
|
169
|
+
// - Will remove non existing masterfiles or masterfiles that start with a '_'
|
|
170
|
+
|
|
171
|
+
spConfig = _modulesTdi.require(spConfigPath);
|
|
172
|
+
sefFile = _modulesTdi.require(sefFilePath);
|
|
173
|
+
|
|
174
|
+
if (!spConfig || !sefFile) _error(`Cannot find required files in TDI submodule. Try updating TDI submodule.`);
|
|
175
|
+
|
|
176
|
+
const newXprFile = (typeof arg === 'string') ? convertToValidFilename(arg) + '.xpr' : null;
|
|
177
|
+
createProjectFile(spConfig, newXprFile);
|
|
178
178
|
};
|
package/src/modules/git/index.js
CHANGED
|
@@ -172,14 +172,14 @@ function updateRepo () {
|
|
|
172
172
|
*/
|
|
173
173
|
function updateSubmodule({dates = [], updateSubmodule: releaseBranchName}) {
|
|
174
174
|
const [dateCustomFrom, dateCustomTo] = dates;
|
|
175
|
-
const
|
|
175
|
+
const targetVersion = typeof releaseBranchName !== 'boolean' ? releaseBranchName : null;
|
|
176
176
|
|
|
177
177
|
if (dateCustomFrom) _warn(`While testing the "TDI commits requiring migration" note that the submodule is not changed.`);
|
|
178
|
-
if (dateCustomFrom && !
|
|
178
|
+
if (dateCustomFrom && !targetVersion) _error(`Specify a release branch for testing the migration, e.g. "--us 5.6".`);
|
|
179
179
|
|
|
180
180
|
// For testing the migrations (dates argument is specified); submodule pull, fetch, updates fail or result in switching to the release-branch; while we want to test the migration in the current submodule branch / symlink to TDI-project. Therefore all submodule actions should not be applied when the dates argument is specified. As the release of the current submodule cannot be determined you also need to specify the toBranchName so you can test the migrations you want.
|
|
181
|
-
const branch = !dateCustomFrom ? getTdiBranch(
|
|
182
|
-
const branchUpgrade = branch.from ? branch.from.
|
|
181
|
+
const branch = !dateCustomFrom ? getTdiBranch(targetVersion) : {'name': `release/${targetVersion}`, 'version': targetVersion};
|
|
182
|
+
const branchUpgrade = branch.from ? compare(branch.from.version, branch.version, '<') : false;
|
|
183
183
|
|
|
184
184
|
if (branchUpgrade) _info(`Current branch '${branch.from.name}' will be updated to '${branch.name}'\nCommon ancestor will be used in selecting TDI commits requiring migration: ${_formatDate(branch.commonAncestor.date)}`);
|
|
185
185
|
_info(`Branch ${branch.name} is ${branch.commitsBehind} commits behind.\n`);
|
|
@@ -203,8 +203,6 @@ function updateSubmodule({dates = [], updateSubmodule: releaseBranchName}) {
|
|
|
203
203
|
const migrations = _modulesTdi.require('git/tdiCommitsRequiringMigration.js');
|
|
204
204
|
const fromDate = dateCustomFrom ? new Date(dateCustomFrom) : branch.commonAncestor?.date ?? dateBeforeUpdate;
|
|
205
205
|
const toDate = dateCustomTo ? new Date(dateCustomTo) : new Date();
|
|
206
|
-
const fromVersion = branch.from?.name?.replace('release/', '');
|
|
207
|
-
const toVersion = branch.name.replace('release/', '');
|
|
208
206
|
|
|
209
207
|
_info(`TDI commits requiring migration between ${_formatDate(fromDate)} and ${_formatDate(toDate)}`);
|
|
210
208
|
// Filter the migrations that should be applied/considered; Also display older releases migrations
|
|
@@ -214,11 +212,11 @@ function updateSubmodule({dates = [], updateSubmodule: releaseBranchName}) {
|
|
|
214
212
|
|
|
215
213
|
if (branchUpgrade) {
|
|
216
214
|
// For branch upgrades, include all migrations for versions newer than the current one, and include new migrations for the current version
|
|
217
|
-
const isTargetBranch = compare(r.release,
|
|
218
|
-
return isTargetBranch || (r.release ===
|
|
215
|
+
const isTargetBranch = compare(r.release, branch.version, '<=') && compare(r.release, branch.from.version, '>');
|
|
216
|
+
return isTargetBranch || (r.release === branch.from.version && withinDateRange);
|
|
219
217
|
} else {
|
|
220
218
|
// For non-branch upgrades, only include new migrations for the current branch
|
|
221
|
-
return r.release ===
|
|
219
|
+
return r.release === branch.version && withinDateRange;
|
|
222
220
|
}
|
|
223
221
|
}));
|
|
224
222
|
|
|
@@ -227,7 +225,7 @@ function updateSubmodule({dates = [], updateSubmodule: releaseBranchName}) {
|
|
|
227
225
|
migrationsFiltered
|
|
228
226
|
.sort((a, b) => Date(a.releases[0].date) > Date(b.releases[0].date) ? 1 : -1)
|
|
229
227
|
.forEach(m => {
|
|
230
|
-
const date = _formatDate(new Date(m.releases.filter(r => branch.
|
|
228
|
+
const date = _formatDate(new Date(m.releases.filter(r => compare(branch.version, r.release, '>='))[0].date));
|
|
231
229
|
relevantMigrationCount += m.callback(date, relevantMigrationCount+1) === 1 ? 1 : 0;
|
|
232
230
|
});
|
|
233
231
|
|
|
@@ -1,201 +1,201 @@
|
|
|
1
|
-
const fs = require('fs-extra');
|
|
2
|
-
const globby = require('globby');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const {Table} = require('console-table-printer');
|
|
5
|
-
|
|
6
|
-
const execGitCommand = require('../../lib/exec-git-command');
|
|
7
|
-
const getTdiBranch = require('../../lib/get-tdi-branch');
|
|
8
|
-
const c = require('../deploy/config');
|
|
9
|
-
const RemoteExec = require('../../lib/remote-exec');
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const getGitInfo = () => {
|
|
13
|
-
// Version info TDI submodule
|
|
14
|
-
const gitSubmoduleInfo = new Table({
|
|
15
|
-
columns: [
|
|
16
|
-
{name: 'property', title: 'TDI - submodule', alignment: 'left'},
|
|
17
|
-
{name: 'value', alignment: 'left'}
|
|
18
|
-
],
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
// Fetch all
|
|
22
|
-
const cmdFetch = execGitCommand('fetch -pf --all', path.join(_paths.repo, _paths.tdi));
|
|
23
|
-
if (cmdFetch.error) _warn(`Fetch failed\n${cmdFetch.error}`);
|
|
24
|
-
|
|
25
|
-
// Set branch name of firstBranch without 'remotes/origin/'
|
|
26
|
-
const tdiBranch = getTdiBranch();
|
|
27
|
-
|
|
28
|
-
// Get number of commits behind
|
|
29
|
-
tdiBranch.commitsBehind = execGitCommand(`rev-list HEAD...origin/${tdiBranch.name} --count`, path.join(_paths.repo, _paths.tdi));
|
|
30
|
-
|
|
31
|
-
// Create table rows for TDI submodule info
|
|
32
|
-
gitSubmoduleInfo.addRow({
|
|
33
|
-
property: 'Commit date',
|
|
34
|
-
value: _formatDate(_git.commitTdi.local().date)
|
|
35
|
-
});
|
|
36
|
-
if (tdiBranch) {
|
|
37
|
-
gitSubmoduleInfo.addRow({
|
|
38
|
-
property: 'Branch',
|
|
39
|
-
value: tdiBranch.name
|
|
40
|
-
});
|
|
41
|
-
gitSubmoduleInfo.addRow({
|
|
42
|
-
property: 'Commits behind',
|
|
43
|
-
value: tdiBranch.commitsBehind
|
|
44
|
-
});
|
|
45
|
-
} else {
|
|
46
|
-
gitSubmoduleInfo.addRow({
|
|
47
|
-
property: 'Branch could not be determined',
|
|
48
|
-
value: ''
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Print TDI submodule info
|
|
53
|
-
gitSubmoduleInfo.printTable();
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const getFileExtractInfo = (sorting) => {
|
|
57
|
-
// version info miscellaneous
|
|
58
|
-
const projects = new Set;
|
|
59
|
-
const types = new Set;
|
|
60
|
-
const versionInfo = new Table({
|
|
61
|
-
columns: [
|
|
62
|
-
{name: 'path', alignment: 'left'},
|
|
63
|
-
{name: 'type', alignment: 'left'},
|
|
64
|
-
{name: 'version', alignment: 'left'},
|
|
65
|
-
{name: 'sort'}
|
|
66
|
-
],
|
|
67
|
-
disabledColumns: ['sort'],
|
|
68
|
-
sort: (a, b) => a.sort.toLowerCase() > b.sort.toLowerCase() ? 1 : -1
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
const versionInfoConfig = _modulesTdi.require('version/versionInfo.js');
|
|
72
|
-
if (versionInfoConfig) {
|
|
73
|
-
|
|
74
|
-
versionInfoConfig.forEach(v => {
|
|
75
|
-
const location = path.join(_paths.repo, v.glob);
|
|
76
|
-
|
|
77
|
-
globby
|
|
78
|
-
.sync(location)
|
|
79
|
-
.forEach(f => {
|
|
80
|
-
const filePathExtract = f.match(/.*(?<path>(cmscustom|site-stylesheets)\/(?<customer>[^/]*)\/(?<project>[^/]*)\/.*)/);
|
|
81
|
-
const path = filePathExtract.groups.path || '';
|
|
82
|
-
const project = filePathExtract.groups.project || '';
|
|
83
|
-
|
|
84
|
-
const fileContent = fs.readFileSync(f).toString();
|
|
85
|
-
v.extracts.forEach(e => {
|
|
86
|
-
const extract = fileContent.match(e.regex);
|
|
87
|
-
if (extract) {
|
|
88
|
-
projects.add(project); // Store the projects where versioninfo is found
|
|
89
|
-
types.add(e.type); // Store the types for which versioninfo is found
|
|
90
|
-
versionInfo.addRow({ // Create row with version information to output
|
|
91
|
-
path,
|
|
92
|
-
sort: `${sorting=='project' ? project : e.type}_2${sorting=='project' ? e.type : extract.groups.version}`, // Output is sorted on project or type: '_2' ensures it is rendered after the empty row and the row with the project name
|
|
93
|
-
type: e.type,
|
|
94
|
-
version: extract.groups.version
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
if (sorting=='project') {
|
|
102
|
-
// For projects containing version information
|
|
103
|
-
projects.forEach(p => {
|
|
104
|
-
versionInfo.addRow({ // Add empty row after project
|
|
105
|
-
path: '',
|
|
106
|
-
sort: `${p}_3`,
|
|
107
|
-
type: '',
|
|
108
|
-
version: ''
|
|
109
|
-
});
|
|
110
|
-
versionInfo.addRow({ // Add row with project name
|
|
111
|
-
path: `-- ${p}:`,
|
|
112
|
-
sort: `${p}_1`,
|
|
113
|
-
type: '',
|
|
114
|
-
version: ''
|
|
115
|
-
}, {
|
|
116
|
-
color: 'yellow'
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
else if (sorting=='type') {
|
|
121
|
-
types.forEach(t => {
|
|
122
|
-
versionInfo.addRow({ // Add empty row after type
|
|
123
|
-
path: '',
|
|
124
|
-
sort: `${t}_3`,
|
|
125
|
-
type: '',
|
|
126
|
-
version: ''
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
versionInfo.printTable();
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
_warn('Version info of miscellaneous items cannot be extracted:\nCannot find required files in TDI submodule. Try updating TDI submodule.');
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
const getServerInfo = (server) => {
|
|
138
|
-
// Remote server info
|
|
139
|
-
// common setup
|
|
140
|
-
_write();
|
|
141
|
-
c.setServer(server);
|
|
142
|
-
|
|
143
|
-
if (!c.envDev) {
|
|
144
|
-
_info(`Remote version info for '${c.server.ftpConfig.host}':\n`);
|
|
145
|
-
new RemoteExec(c.server.ftpConfig).add('sudo ~root/scripts/version.sh', 'STDOUT').process();
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
_info('For development environments no server version information is available. Check rancher / database for this information.\nAdd the --server option with a non-dev environment to see version information for that server.');
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
module.exports = function info (argv) {
|
|
154
|
-
|
|
155
|
-
if (argv.doctypes) {
|
|
156
|
-
_info('Document type information for this git repository\n');
|
|
157
|
-
|
|
158
|
-
const doctypesInfo = new Table({
|
|
159
|
-
columns: [
|
|
160
|
-
{name: 'id', alignment: 'right'},
|
|
161
|
-
{name: 'name', alignment: 'left'},
|
|
162
|
-
{name: 'paths', alignment: 'left'}
|
|
163
|
-
],
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
globby
|
|
167
|
-
.sync(_paths.repo + '/database/config/**/txd_document_types.sql')
|
|
168
|
-
.forEach((p, i, a) => {
|
|
169
|
-
fs.readFileSync(p).toString().match(/select([\s\S]+?)from\s+dual/gmi)
|
|
170
|
-
.forEach((dtRow, i, a) => {
|
|
171
|
-
const ntSqlInsert = fs.readFileSync(p.replace('txd_document_types', 'txd_node_types')).toString().match(/select(.*?)from\s+dual/s)[1];
|
|
172
|
-
const id = dtRow.match(/(\d+) id/)?.[1];
|
|
173
|
-
const name = dtRow.match(/'([^']+)' display_name/)?.[1];
|
|
174
|
-
const dbPath = p.match(/(database\/config\/(:?.*)\/)txd_document_types.sql/i)?.[1];
|
|
175
|
-
const xincl = ntSqlInsert.match(/'([^']+)' xsl_prep_inc/)?.[1] ?? dtRow.match(/'([^']+)' xsl_xincludes/)[1];
|
|
176
|
-
const prPath = xincl.replace('prepare_xincludes.xsl', '');
|
|
177
|
-
|
|
178
|
-
doctypesInfo.addRows([
|
|
179
|
-
{id, name, paths: 'config/cmscustom/'+ prPath},
|
|
180
|
-
{paths: dbPath}
|
|
181
|
-
]);
|
|
182
|
-
|
|
183
|
-
if (i!==a.length-1) doctypesInfo.addRow({});
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
if (i!==a.length-1) doctypesInfo.addRow({});
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
doctypesInfo.printTable();
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (argv.versions) {
|
|
194
|
-
_info('Version information for this git repository\n');
|
|
195
|
-
|
|
196
|
-
getGitInfo();
|
|
197
|
-
getFileExtractInfo(argv.versions);
|
|
198
|
-
getServerInfo(argv.server);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
};
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const globby = require('globby');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const {Table} = require('console-table-printer');
|
|
5
|
+
|
|
6
|
+
const execGitCommand = require('../../lib/exec-git-command');
|
|
7
|
+
const getTdiBranch = require('../../lib/get-tdi-branch');
|
|
8
|
+
const c = require('../deploy/config');
|
|
9
|
+
const RemoteExec = require('../../lib/remote-exec');
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
const getGitInfo = () => {
|
|
13
|
+
// Version info TDI submodule
|
|
14
|
+
const gitSubmoduleInfo = new Table({
|
|
15
|
+
columns: [
|
|
16
|
+
{name: 'property', title: 'TDI - submodule', alignment: 'left'},
|
|
17
|
+
{name: 'value', alignment: 'left'}
|
|
18
|
+
],
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Fetch all
|
|
22
|
+
const cmdFetch = execGitCommand('fetch -pf --all', path.join(_paths.repo, _paths.tdi));
|
|
23
|
+
if (cmdFetch.error) _warn(`Fetch failed\n${cmdFetch.error}`);
|
|
24
|
+
|
|
25
|
+
// Set branch name of firstBranch without 'remotes/origin/'
|
|
26
|
+
const tdiBranch = getTdiBranch();
|
|
27
|
+
|
|
28
|
+
// Get number of commits behind
|
|
29
|
+
tdiBranch.commitsBehind = execGitCommand(`rev-list HEAD...origin/${tdiBranch.name} --count`, path.join(_paths.repo, _paths.tdi));
|
|
30
|
+
|
|
31
|
+
// Create table rows for TDI submodule info
|
|
32
|
+
gitSubmoduleInfo.addRow({
|
|
33
|
+
property: 'Commit date',
|
|
34
|
+
value: _formatDate(_git.commitTdi.local().date)
|
|
35
|
+
});
|
|
36
|
+
if (tdiBranch) {
|
|
37
|
+
gitSubmoduleInfo.addRow({
|
|
38
|
+
property: 'Branch',
|
|
39
|
+
value: tdiBranch.name
|
|
40
|
+
});
|
|
41
|
+
gitSubmoduleInfo.addRow({
|
|
42
|
+
property: 'Commits behind',
|
|
43
|
+
value: tdiBranch.commitsBehind
|
|
44
|
+
});
|
|
45
|
+
} else {
|
|
46
|
+
gitSubmoduleInfo.addRow({
|
|
47
|
+
property: 'Branch could not be determined',
|
|
48
|
+
value: ''
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Print TDI submodule info
|
|
53
|
+
gitSubmoduleInfo.printTable();
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const getFileExtractInfo = (sorting) => {
|
|
57
|
+
// version info miscellaneous
|
|
58
|
+
const projects = new Set;
|
|
59
|
+
const types = new Set;
|
|
60
|
+
const versionInfo = new Table({
|
|
61
|
+
columns: [
|
|
62
|
+
{name: 'path', alignment: 'left'},
|
|
63
|
+
{name: 'type', alignment: 'left'},
|
|
64
|
+
{name: 'version', alignment: 'left'},
|
|
65
|
+
{name: 'sort'}
|
|
66
|
+
],
|
|
67
|
+
disabledColumns: ['sort'],
|
|
68
|
+
sort: (a, b) => a.sort.toLowerCase() > b.sort.toLowerCase() ? 1 : -1
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const versionInfoConfig = _modulesTdi.require('version/versionInfo.js');
|
|
72
|
+
if (versionInfoConfig) {
|
|
73
|
+
|
|
74
|
+
versionInfoConfig.forEach(v => {
|
|
75
|
+
const location = path.join(_paths.repo, v.glob);
|
|
76
|
+
|
|
77
|
+
globby
|
|
78
|
+
.sync(location)
|
|
79
|
+
.forEach(f => {
|
|
80
|
+
const filePathExtract = f.match(/.*(?<path>(cmscustom|site-stylesheets)\/(?<customer>[^/]*)\/(?<project>[^/]*)\/.*)/);
|
|
81
|
+
const path = filePathExtract.groups.path || '';
|
|
82
|
+
const project = filePathExtract.groups.project || '';
|
|
83
|
+
|
|
84
|
+
const fileContent = fs.readFileSync(f).toString();
|
|
85
|
+
v.extracts.forEach(e => {
|
|
86
|
+
const extract = fileContent.match(e.regex);
|
|
87
|
+
if (extract) {
|
|
88
|
+
projects.add(project); // Store the projects where versioninfo is found
|
|
89
|
+
types.add(e.type); // Store the types for which versioninfo is found
|
|
90
|
+
versionInfo.addRow({ // Create row with version information to output
|
|
91
|
+
path,
|
|
92
|
+
sort: `${sorting=='project' ? project : e.type}_2${sorting=='project' ? e.type : extract.groups.version}`, // Output is sorted on project or type: '_2' ensures it is rendered after the empty row and the row with the project name
|
|
93
|
+
type: e.type,
|
|
94
|
+
version: extract.groups.version
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
if (sorting=='project') {
|
|
102
|
+
// For projects containing version information
|
|
103
|
+
projects.forEach(p => {
|
|
104
|
+
versionInfo.addRow({ // Add empty row after project
|
|
105
|
+
path: '',
|
|
106
|
+
sort: `${p}_3`,
|
|
107
|
+
type: '',
|
|
108
|
+
version: ''
|
|
109
|
+
});
|
|
110
|
+
versionInfo.addRow({ // Add row with project name
|
|
111
|
+
path: `-- ${p}:`,
|
|
112
|
+
sort: `${p}_1`,
|
|
113
|
+
type: '',
|
|
114
|
+
version: ''
|
|
115
|
+
}, {
|
|
116
|
+
color: 'yellow'
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
else if (sorting=='type') {
|
|
121
|
+
types.forEach(t => {
|
|
122
|
+
versionInfo.addRow({ // Add empty row after type
|
|
123
|
+
path: '',
|
|
124
|
+
sort: `${t}_3`,
|
|
125
|
+
type: '',
|
|
126
|
+
version: ''
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
versionInfo.printTable();
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
_warn('Version info of miscellaneous items cannot be extracted:\nCannot find required files in TDI submodule. Try updating TDI submodule.');
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const getServerInfo = (server) => {
|
|
138
|
+
// Remote server info
|
|
139
|
+
// common setup
|
|
140
|
+
_write();
|
|
141
|
+
c.setServer(server);
|
|
142
|
+
|
|
143
|
+
if (!c.envDev) {
|
|
144
|
+
_info(`Remote version info for '${c.server.ftpConfig.host}':\n`);
|
|
145
|
+
new RemoteExec(c.server.ftpConfig).add('sudo ~root/scripts/version.sh', 'STDOUT').process();
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
_info('For development environments no server version information is available. Check rancher / database for this information.\nAdd the --server option with a non-dev environment to see version information for that server.');
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
module.exports = function info (argv) {
|
|
154
|
+
|
|
155
|
+
if (argv.doctypes) {
|
|
156
|
+
_info('Document type information for this git repository\n');
|
|
157
|
+
|
|
158
|
+
const doctypesInfo = new Table({
|
|
159
|
+
columns: [
|
|
160
|
+
{name: 'id', alignment: 'right'},
|
|
161
|
+
{name: 'name', alignment: 'left'},
|
|
162
|
+
{name: 'paths', alignment: 'left'}
|
|
163
|
+
],
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
globby
|
|
167
|
+
.sync(_paths.repo + '/database/config/**/txd_document_types.sql')
|
|
168
|
+
.forEach((p, i, a) => {
|
|
169
|
+
fs.readFileSync(p).toString().match(/select([\s\S]+?)from\s+dual/gmi)
|
|
170
|
+
.forEach((dtRow, i, a) => {
|
|
171
|
+
const ntSqlInsert = fs.readFileSync(p.replace('txd_document_types', 'txd_node_types')).toString().match(/select(.*?)from\s+dual/s)[1];
|
|
172
|
+
const id = dtRow.match(/(\d+) id/)?.[1];
|
|
173
|
+
const name = dtRow.match(/'([^']+)' display_name/)?.[1];
|
|
174
|
+
const dbPath = p.match(/(database\/config\/(:?.*)\/)txd_document_types.sql/i)?.[1];
|
|
175
|
+
const xincl = ntSqlInsert.match(/'([^']+)' xsl_prep_inc/)?.[1] ?? dtRow.match(/'([^']+)' xsl_xincludes/)[1];
|
|
176
|
+
const prPath = xincl.replace('prepare_xincludes.xsl', '');
|
|
177
|
+
|
|
178
|
+
doctypesInfo.addRows([
|
|
179
|
+
{id, name, paths: 'config/cmscustom/'+ prPath},
|
|
180
|
+
{paths: dbPath}
|
|
181
|
+
]);
|
|
182
|
+
|
|
183
|
+
if (i!==a.length-1) doctypesInfo.addRow({});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
if (i!==a.length-1) doctypesInfo.addRow({});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
doctypesInfo.printTable();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (argv.versions) {
|
|
194
|
+
_info('Version information for this git repository\n');
|
|
195
|
+
|
|
196
|
+
getGitInfo();
|
|
197
|
+
getFileExtractInfo(argv.versions);
|
|
198
|
+
getServerInfo(argv.server);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
};
|