@tangelo/tangelo-configuration-toolkit 1.12.0 → 1.13.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/index.js CHANGED
@@ -72,7 +72,7 @@ try { global._appconfig = _paths.appconfig && fs.readJsonSync(_paths.appconfig)
72
72
  catch({message}) { _error('Error in '+message); }
73
73
 
74
74
  _appconfig.sharedConfigPath = path.resolve(_paths.appconfig || '', '..', _appconfig.sharedConfigPath || '', appname+'-appconfig.json');
75
- _appconfig.shared = fs.readJsonSync(_appconfig.sharedConfigPath, {throws: false}) || {};
75
+ _appconfig.shared = fs.readJsonSync(_appconfig.sharedConfigPath, {throws: false}) || {};
76
76
 
77
77
 
78
78
  global._git = {
@@ -81,22 +81,21 @@ global._git = {
81
81
  return _appdata.gitUser;
82
82
  },
83
83
  commitLocal () {
84
- return this.cache = this.cache ||
85
- execGitCommand(`log -1 --format=%D;%H;%cd --date=iso-strict`, _paths.repo, ['branch', 'hash', 'date']);
84
+ this.cache ??= execGitCommand(`log -1 --format=%D;%H;%cd --date=iso-strict`, _paths.repo, ['branch', 'hash', 'date']);
85
+ return this.cache;
86
86
  },
87
87
  commitRemote () {
88
- return this.cache = this.cache ||
89
- execGitCommand('log -1 --format=%cd --date=iso-strict origin/'+_git.commitLocal().branch, _paths.repo, ['date']);
88
+ this.cache ??= execGitCommand('log -1 --format=%cd --date=iso-strict origin/'+_git.commitLocal().branch, _paths.repo, ['date']);
89
+ return this.cache;
90
90
  },
91
91
  commitTdi: {
92
92
  local () {
93
- return this.cache = this.cache ||
94
- execGitCommand(`log -1 --format=%D;%H;%cd --date=iso-strict`, path.join(_paths.repo, _paths.tdi), ['tags', 'hash', 'date']);
93
+ this.cache ??= execGitCommand(`log -1 --format=%D;%H;%cd --date=iso-strict`, path.join(_paths.repo, _paths.tdi), ['tags', 'hash', 'date']);
94
+ return this.cache;
95
95
  },
96
96
  after (commitHash) {
97
- if (this['cache-'+commitHash] != undefined) return this['cache-'+commitHash];
98
- return this['cache-'+commitHash] =
99
- execGitCommand(`merge-base --is-ancestor ${commitHash} ${_git.commitTdi.local().hash}`, path.join(_paths.repo, _paths.tdi), null, 0);
97
+ this['cache-'+commitHash] ??= execGitCommand(`merge-base --is-ancestor ${commitHash} ${_git.commitTdi.local().hash}`, path.join(_paths.repo, _paths.tdi), null, 0);
98
+ return this['cache-'+commitHash];
100
99
  },
101
100
  fontoVersions: [ // latest commits first
102
101
  {commitHash: 'e599766', regex: /^7\.1[45]\./},
@@ -127,7 +126,6 @@ global._isPre42 = fs.existsSync(path.join(_paths.repo, _paths.tdi, 'create_new_p
127
126
  global._isPre51 = !fs.existsSync(path.join(_paths.repo, _paths.tdi, 'src')); // folder changed in 5.1 (check new folder because old one could still exist after branch switch)
128
127
 
129
128
 
130
-
131
129
  process.on('beforeExit', () => {
132
130
  _write(); // print empty line before and after update check
133
131
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangelo/tangelo-configuration-toolkit",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "description": "Tangelo Configuration Toolkit is a command-line toolkit which offers support for developing a Tangelo configuration.",
5
5
  "bin": {
6
6
  "tct": "bin/index.js",
package/src/cli.js CHANGED
@@ -25,7 +25,7 @@ module.exports = function cli () {
25
25
  init: {alias: 'i', desc: 'Create repository content structure', conflicts: ['p', 's', 'c']},
26
26
  project: {alias: 'p', desc: 'Create project configuration', conflicts: ['i', 's', 'c']},
27
27
  symlinks: {alias: 's', desc: 'Recreate symlinks to TDI', conflicts: ['p', 'i', 'c']},
28
- config: {alias: 'c', desc: 'Create repo-config file', conflicts: ['p', 'i', 's'], hidden: _git.commitTdi.after(_git.commitTdi.stopUsingRepoconfigFile)},
28
+ config: {alias: 'c', desc: 'Create repo-config file', conflicts: ['p', 'i', 's'], hidden: true},
29
29
  oxygen: {alias: 'x', desc: 'Create or update oXygen project file (.xpr)', conflicts: ['p', 'i', 'c']}
30
30
  },
31
31
  handler: require('./modules/build')
@@ -92,15 +92,17 @@ module.exports = function cli () {
92
92
  remove: {alias: 'r', desc: 'Remove project configuration', conflicts: ['i', 'c', 'g']}
93
93
  },
94
94
  handler: require('./modules/sql')
95
- }).command({
96
- command: 'versions',
97
- aliases: ['v'],
98
- desc: 'Show version information',
95
+ })
96
+ .command({
97
+ command: 'info',
98
+ aliases: ['i'],
99
+ desc: 'Show project information',
99
100
  builder: {
100
- find: {alias: 'f', desc: `Find all version information [choices: "sort-project"(default),"sort-type"]`},
101
+ doctypes: {alias: 'd', desc: `List document-types information`},
102
+ versions: {alias: 'v', desc: `Find all version information, sorted by project or type`, choices: ['project', 'type'], conflicts: ['d']},
101
103
  server: {alias: 's', desc: 'Pass server name (set in config file)', default: _appconfig.defaultServer}
102
104
  },
103
- handler: require('./modules/version')
105
+ handler: require('./modules/info')
104
106
  })
105
107
  .recommendCommands()
106
108
  .option('config', {alias: 'c', desc: 'Show loaded appconfig', global: false})
@@ -18,11 +18,11 @@ const createSymlink = (t, p) => {
18
18
  const createSymlinks = () => {
19
19
  _info('Creating symlinks:');
20
20
  const src = _isPre51 ? 'sources' : 'src';
21
- createSymlink(src + '/config/cmscustom/tdi', 'config/cmscustom/tdi', 'TDI');
21
+ createSymlink(src + '/config/cmscustom/tdi', 'config/cmscustom/tdi');
22
22
  globby
23
23
  .sync('config/cmscustom/!(tdi)/**/fonto')
24
24
  .forEach(p => {
25
- createSymlink(src + '/config/cmscustom/tdi/fonto/packages-shared', p + '/packages-shared', 'Fonto');
25
+ createSymlink(src + '/config/cmscustom/tdi/fonto/packages-shared', p + '/packages-shared');
26
26
  });
27
27
  };
28
28
 
@@ -109,7 +109,6 @@ module.exports = function build (argv) {
109
109
  _repoconfig.update({customer, projects, applink: 'None'});
110
110
 
111
111
  _write(`\nFile '${_paths.repoconfig}' has been created.`);
112
- _repoconfig.projects;
113
112
  });
114
113
  }
115
114
 
@@ -11,6 +11,8 @@ const siteStylesheetsPath = 'config/txp/site-stylesheets/';
11
11
  const masterFiles = new Set;
12
12
  const transformationScenarios = [];
13
13
 
14
+ const convertToValidFilename = (string) => string.replace(/[\/|\\:*?"<>]/g, " ");
15
+
14
16
  const createProjectFile = (config) => {
15
17
  _info('Initializing xpr file(s):');
16
18
  const xprFiles = globby.sync(`*.xpr`);
@@ -20,7 +22,7 @@ const createProjectFile = (config) => {
20
22
  else {
21
23
  const customers = new Set;
22
24
  _repoconfig.forEach(p => customers.add(p.customer_name));
23
- xprFiles.push([...customers].join(' - ') + '.xpr');
25
+ xprFiles.push(convertToValidFilename([...customers].join(' - ')) + '.xpr');
24
26
  fs.copySync(path.join(_paths.repo, 'tangelo-default-implementation/src/[customer].xpr'), path.join(_paths.repo, xprFiles[0]));
25
27
  _write(`Created: '${xprFiles[0]}'`);
26
28
  }
@@ -84,7 +84,7 @@ module.exports = {
84
84
  .trim()
85
85
  .replace(/^#.+/gm, '') // remove comments
86
86
  .split(/\s+/) // split on lines
87
- .filter(p => !p.match(/^database\/|\/tdi|\/fonto/)) // filter paths that should be copied
87
+ .filter(p => !p.match(/(^database\/)|(\/tdi)|(\/fonto)/)) // filter paths that should be copied
88
88
  .map(p => '!' + (p.match(/^config/) ? p : '**/' + p.split('**/').pop()) + (p.match(/\/$/) ? '**' : '')) // negate expressions, remove base dir, suffix folders with **
89
89
  ;
90
90
 
@@ -110,7 +110,7 @@ module.exports = {
110
110
  if (this.deliveryPack && transferPattern.includes(_paths.tdi)) this.transferPatterns.push(`${_paths.tdi}/src/database/create*.sql`); // create(_exists).sql is called by tdi install
111
111
 
112
112
  // add time parameters to all xopus requests to overcome cache
113
- const ts = new Date().toISOString().replace(/-|:/g, '').substring(0, 15);
113
+ const ts = new Date().toISOString().replace(/[-:]/g, '').substring(0, 15);
114
114
  this.replaceStrings = [
115
115
  [/((xsd|xsl|src|iconsrc)="[^"?]+)"/g, `$1?_=${ts}"`, '**/xopus/xml/*'],
116
116
  [/(schemaLocation="[^"?]+)"/g, `$1?_=${ts}"`, '**/xopus/xsd/*'],
@@ -127,7 +127,7 @@ module.exports = {
127
127
  const schemasPerElement = {};
128
128
  Object.entries(rootSchemas).forEach(([path, obj]) => {
129
129
  const data = execSync(`${fdt} elements --schema packages/${obj.packageName}/src/assets/schemas/${obj.packageName}.json -C name`, {encoding: 'UTF-8'});
130
- const elements = data.replace(/^.*?Name\*|Printed name\*.*$/gs, '').split(/\s+/);
130
+ const elements = data.replace(/(^.*?Name\*)|(Printed name\*.*$)/gs, '').split(/\s+/);
131
131
  const customElements = [...new Set(elements)].filter(e => e && !ignoreElements.includes(e));
132
132
 
133
133
  customElements.forEach(e => {
@@ -176,7 +176,7 @@ module.exports = {
176
176
  const schemasPerAttribute = {};
177
177
  Object.entries(rootSchemas).forEach(([path, obj]) => {
178
178
  const data = execSync(`${fdt} attributes --schema packages/${obj.packageName}/src/assets/schemas/${obj.packageName}.json`, {encoding: 'UTF-8'});
179
- const attributes = data.replace(/^.*?Default value\s+|\s+Printed name\*.*$/gs, '').split(/\n\s+/).map(a => a.split(/\s+/)).map(a =>
179
+ const attributes = data.replace(/(^.*?Default value\s+)|(\s+Printed name\*.*$)/gs, '').split(/\n\s+/).map(a => a.split(/\s+/)).map(a =>
180
180
  a[0] + (a[2]=='required' ? ' (required)' : '') + (a[3]=='-' ? ' (no default)' : '')
181
181
  );
182
182
  const customAttributes = [...new Set(attributes)].filter(e => e && !ignoreAttributes.includes(e.replace(/ .*/, '')));
@@ -5,7 +5,7 @@ const globby = require('globby');
5
5
  const path = require('path');
6
6
 
7
7
 
8
- const fdtCommand = (fv) => `npx -y ${_packages.FDT.name}@${fv.replace(/^(7\.|8\.[12]\.).*/, '3.12.0')}`;
8
+ const fdtCommand = (fv) => `npx -y ${_packages.FDT.name}@${fv.replace(/^(7\.|8\.[012]\.).*/, '3.12.0')}`;
9
9
 
10
10
  module.exports = function fonto (argv) {
11
11
 
@@ -29,7 +29,7 @@ module.exports = function fonto (argv) {
29
29
  process.chdir(_paths.apply || '.');
30
30
 
31
31
  // find fonto instances by searching for fonto/manifest.json files
32
- const fontoPaths = globby.sync(['**/fonto/manifest.json', `!${_paths.tdi}/**`])
32
+ const fontoPaths = globby.sync(['**/fonto/manifest.json', 'manifest.json', `!${_paths.tdi}/**`])
33
33
  .map(p => ([p.replace('manifest.json', ''), fs.readJsonSync(p).sdkVersion.replace(/Nightlies.*/, 'nightly')])
34
34
  );
35
35
 
@@ -1,14 +1,15 @@
1
- const fs = require('fs-extra');
2
- const globby = require('globby');
3
- const path = require('path');
4
- const {Table} = require('console-table-printer');
5
- const execGitCommand = require('../../lib/exec-git-command');
6
- const c = require('../deploy/config');
7
- const {remote} = require('../deploy/execute');
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 c = require('../deploy/config');
8
+ const {remote} = require('../deploy/execute');
9
+
8
10
 
9
11
  const getGitInfo = () => {
10
12
  // Version info TDI submodule
11
- const branchInfo = [];
12
13
  const gitSubmoduleInfo = new Table({
13
14
  columns: [
14
15
  {name: 'property', title: 'TDI - submodule', alignment: 'left'},
@@ -21,18 +22,12 @@ const getGitInfo = () => {
21
22
 
22
23
  // Get branches containing TDI HEAD commit
23
24
  const releaseBranches = execGitCommand(`branch --all --contains ${_git.commitTdi.local().hash}`, path.join(_paths.repo, _paths.tdi)).match(/release\/[^\s]+/gsm);
24
- if (releaseBranches) {
25
- releaseBranches.forEach(b => {
26
- // Get number of commits behind
27
- const count = execGitCommand(`rev-list HEAD...origin/${b} --count`, path.join(_paths.repo, _paths.tdi));
28
- // _info(`debug: [${b}]:${count}`);
29
- // Push number of commits behind to branchInfo
30
- branchInfo.push({name: b, commitsBehind: count});
31
- });
32
- }
33
-
25
+ if (!releaseBranches) _error('Could not retrieve TDI release branches');
34
26
  // Get the first possible branch; prefer release/5.1 over release/5.2:
35
- const firstBranch = branchInfo.sort((a, b) => a.name > b.name ? 1 : -1)[0];
27
+ releaseBranches.sort((a, b) => a.name > b.name ? 1 : -1);
28
+ const firstBranch = {name: releaseBranches[0]};
29
+ // Get number of commits behind
30
+ firstBranch.commitsBehind = execGitCommand(`rev-list HEAD...origin/${firstBranch.name} --count`, path.join(_paths.repo, _paths.tdi));
36
31
 
37
32
  // Create table rows for TDI submodule info
38
33
  gitSubmoduleInfo.addRow({
@@ -59,9 +54,8 @@ const getGitInfo = () => {
59
54
  gitSubmoduleInfo.printTable();
60
55
  };
61
56
 
62
- const getFileExtractInfo = (argv) => {
57
+ const getFileExtractInfo = (sorting) => {
63
58
  // version info miscellaneous
64
- const sorting = argv.find.toString().includes('sort-type') ? 'type' : 'project';
65
59
  const projects = new Set;
66
60
  const types = new Set;
67
61
  const versionInfoConfigPath = path.join(_paths.repo, _paths.tdi, 'tct/version/versionInfo.js');
@@ -86,8 +80,8 @@ const getFileExtractInfo = (argv) => {
86
80
  .sync(location)
87
81
  .forEach(f => {
88
82
  const filePathExtract = f.match(/.*(?<path>(cmscustom|site-stylesheets)\/(?<customer>[^/]*)\/(?<project>[^/]*)\/.*)/);
89
- const path = filePathExtract.groups.path ? filePathExtract.groups.path : '';
90
- const project = filePathExtract.groups.project ? filePathExtract.groups.project : '';
83
+ const path = filePathExtract.groups.path || '';
84
+ const project = filePathExtract.groups.project || '';
91
85
 
92
86
  const fileContent = fs.readFileSync(f).toString();
93
87
  v.extracts.forEach(e => {
@@ -124,8 +118,8 @@ const getFileExtractInfo = (argv) => {
124
118
  color: 'yellow'
125
119
  });
126
120
  });
127
- } else
128
- if (sorting=='type') {
121
+ }
122
+ else if (sorting=='type') {
129
123
  types.forEach(t => {
130
124
  versionInfo.addRow({ // Add empty row after type
131
125
  path: '',
@@ -136,30 +130,73 @@ const getFileExtractInfo = (argv) => {
136
130
  });
137
131
  }
138
132
  versionInfo.printTable();
139
- } else {
133
+ }
134
+ else {
140
135
  _warn('Version info of miscellaneous items cannot be extracted:\nCannot find required files in TDI submodule. Try updating TDI submodule.');
141
136
  }
142
137
  };
143
138
 
144
- const getServerInfo = (argv) => {
139
+ const getServerInfo = (server) => {
145
140
  // Remote server info
146
141
  // common setup
147
142
  _write();
148
- c.setServer(argv.server);
143
+ c.setServer(server);
149
144
 
150
145
  if (!c.envDev) {
151
146
  _info(`Remote version info for '${c.server.ftpConfig.host}':\n`);
152
147
  remote.add('sudo ~root/scripts/version.sh', '').process();
153
- } else {
148
+ }
149
+ else {
154
150
  _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.');
155
151
  }
156
152
  };
157
153
 
158
- module.exports = function version (argv) {
159
- _info('Version information of this git repository\n');
160
154
 
161
- getGitInfo(argv);
162
- getFileExtractInfo(argv);
163
- getServerInfo(argv);
155
+ module.exports = function info (argv) {
156
+
157
+ if (argv.doctypes) {
158
+ _info('Document type information for this git repository\n');
159
+
160
+ const doctypesInfo = new Table({
161
+ columns: [
162
+ {name: 'id', alignment: 'right'},
163
+ {name: 'name', alignment: 'left'},
164
+ {name: 'paths', alignment: 'left'}
165
+ ],
166
+ });
167
+
168
+ globby
169
+ .sync(_paths.repo + '/database/config/**/txd_document_types.sql')
170
+ .forEach((p, i, a) => {
171
+ fs.readFileSync(p).toString().match(/select([\s\S]+?)from\s+dual/gmi)
172
+ .forEach((dtRow, i, a) => {
173
+ const ntSqlInsert = fs.readFileSync(p.replace('txd_document_types', 'txd_node_types')).toString().match(/select(.*?)from\s+dual/s)[1];
174
+ const id = dtRow.match(/(\d+) id/)?.[1];
175
+ const name = dtRow.match(/'([^']+)' display_name/)?.[1];
176
+ const dbPath = p.match(/(database\/config\/(:?.*)\/)txd_document_types.sql/i)?.[1];
177
+ const prPath = ntSqlInsert.match(/'([^']+)' xsl_prep_inc/)[1].replace('prepare_xincludes.xsl','');
178
+
179
+ doctypesInfo.addRows([
180
+ {id, name, paths: 'config/cmscustom/'+ prPath},
181
+ {paths: dbPath}
182
+ ]);
183
+
184
+ if (i!==a.length-1) doctypesInfo.addRow({});
185
+ });
186
+
187
+ if (i!==a.length-1) doctypesInfo.addRow({});
188
+ });
189
+
164
190
 
165
- };
191
+ doctypesInfo.printTable();
192
+ }
193
+
194
+ if (argv.versions) {
195
+ _info('Version information for this git repository\n');
196
+
197
+ getGitInfo();
198
+ getFileExtractInfo(argv.versions);
199
+ getServerInfo(argv.server);
200
+ }
201
+
202
+ };
@@ -52,9 +52,10 @@ module.exports = function steps (step, dry, filter) {
52
52
  }
53
53
 
54
54
  let filesModCount = 0;
55
- for (let i=0; i<20 && !dry && r.files[0]; i++) { // execute repeatedly for modified files only (with safety limit of 20)
55
+ for (let i=0; i<20 && r.files[0]; i++) { // execute repeatedly for modified files only (with safety limit of 20)
56
56
  r.files = rif.sync(r).filter(f => f.hasChanged).map(f => f.file);
57
57
  if (i==0) filesModCount = r.files.length; // save count only after first run (after this only subsets are processed)
58
+ if (dry) break;
58
59
  }
59
60
 
60
61
  _write('Files modified:', filesModCount);