@tangelo/tangelo-configuration-toolkit 1.7.0 → 1.8.0-beta.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 CHANGED
@@ -4,7 +4,7 @@ Tangelo Configuration Toolkit is a command-line toolkit which offers support for
4
4
 
5
5
  ## Installation
6
6
 
7
- The toolkit requires [NPM](https://www.npmjs.com/get-npm) on [Node.js®](https://nodejs.org/) version 12.x or 14.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:
7
+ The toolkit requires [NPM](https://www.npmjs.com/get-npm) on [Node.js®](https://nodejs.org/) (at least version 12.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
8
 
9
9
  npm i -g @tangelo/tangelo-configuration-toolkit
10
10
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangelo/tangelo-configuration-toolkit",
3
- "version": "1.7.0",
3
+ "version": "1.8.0-beta.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",
@@ -20,31 +20,31 @@
20
20
  "babel-core": "^6.26.3",
21
21
  "babel-preset-es2015-without-strict": "0.0.4",
22
22
  "cli-spinner": "^0.2.10",
23
- "del": "^5.1.0",
23
+ "del": "^6.0.0",
24
24
  "event-stream": "^4.0.1",
25
25
  "find-up": "^5.0.0",
26
- "fs-extra": "^9.0.1",
27
26
  "globby": "^6.1.0",
27
+ "fs-extra": "^10.0.0",
28
28
  "gulp": "^4.0.2",
29
29
  "gulp-babel": "^7.0.1",
30
30
  "gulp-eol": "^0.2.0",
31
- "gulp-filter": "^6.0.0",
31
+ "gulp-filter": "^7.0.0",
32
32
  "gulp-plumber": "^1.2.1",
33
33
  "gulp-print": "^5.0.2",
34
- "gulp-sass": "^4.1.0",
34
+ "gulp-sass": "^5.0.0",
35
35
  "gulp-simple-rename": "^0.1.3",
36
- "gulp-sourcemaps": "^2.6.5",
37
- "inquirer": "^7.3.3",
38
- "istextorbinary": "^5.11.0",
36
+ "gulp-sourcemaps": "^3.0.0",
37
+ "inquirer": "^8.2.0",
38
+ "istextorbinary": "^6.0.0",
39
39
  "minimatch": "^3.0.4",
40
- "node-ssh": "^10.0.0",
40
+ "node-ssh": "^12.0.2",
41
41
  "object-assign-deep": "^0.4.0",
42
- "replace-in-file": "^3.4.4",
42
+ "replace-in-file": "^6.0.0",
43
+ "sass": "^1.43.4",
43
44
  "saxon-js": "^2.3.0",
44
45
  "scp2": "^0.5.0",
45
- "selfupdate": "^1.1.0",
46
46
  "tiny-lr": "^2.0.0",
47
- "yargs": "^16.0.3"
47
+ "yargs": "^16.2.0"
48
48
  },
49
49
  "repository": {
50
50
  "type": "git",
package/src/cli.js CHANGED
@@ -1,10 +1,6 @@
1
- const fs = require('fs-extra');
2
- const selfupdate = require('selfupdate');
3
- const yargs = require('yargs');
4
-
5
-
6
- const updateJsonFile = (path, json = {}, obj = {}) => fs.writeJsonSync(path, Object.assign(json, obj), {spaces: 2});
7
-
1
+ const fs = require('fs-extra');
2
+ const yargs = require('yargs');
3
+ const {getCurrentPackageVersion, getLatestPackageVersion, updatePackage} = require('./lib/npm-package-update');
8
4
 
9
5
  module.exports = function cli () {
10
6
 
@@ -100,6 +96,7 @@ module.exports = function cli () {
100
96
  .recommendCommands()
101
97
  .option('config', {alias: 'c', desc: 'Show loaded appconfig', global: false})
102
98
  .option('update', {alias: 'u', desc: 'Update this package', global: false})
99
+ .option('update-fdt', {alias: 'uf', desc: 'Update the FDT package', global: false})
103
100
  .version(false)
104
101
  .help(false)
105
102
  .example([
@@ -126,27 +123,52 @@ module.exports = function cli () {
126
123
  _write(_appconfig);
127
124
  }
128
125
 
129
- if (argv.update) {
130
- _info('Updating...');
131
- selfupdate.update(_package, (error, version) => {
132
- if (!error) updateJsonFile(_paths.appdata, _appdata, {versionLastChecked: new Date(), versionIsLatest: true});
133
- _write((error||{}).message || 'Updated to version ' + version);
134
- });
126
+ if (argv.updateTct) {
127
+ _info('Updating TCT...');
128
+ getLatestPackageVersion({package: 'TCT', version: _package.version})
129
+ .then(updatePackage)
130
+ ;
131
+ }
132
+
133
+ if (argv.updateFdt) {
134
+ _info('Updating FDT...');
135
+ getCurrentPackageVersion({package: 'FDT'})
136
+ .then(getLatestPackageVersion)
137
+ .then(updatePackage)
138
+ ;
135
139
  }
136
140
 
137
141
  }
138
142
 
139
143
 
144
+ let checkUpdatesDone = false;
145
+
140
146
  process.on('beforeExit', () => {
141
- _write(); // always end with empty line
142
147
 
143
- if (!argv.hasOwnProperty('update') && _appdata.versionIsLatest && new Date() - new Date(_appdata.versionLastChecked || 0) > 1000*3600*24*3) { // check every 3 days
148
+ if (_appdata._changed) {
149
+ delete _appdata._changed;
150
+ fs.writeJsonSync(_paths.appdata, _appdata, {spaces: 2});
151
+ }
152
+
153
+ _write(); // print empty line before and after update check
154
+
155
+ if (!(argv.updateTct || argv.updateFdt) && // not when doing update
156
+ (!_appdata.updateCheckTCT.versionAvailable || !_appdata.updateCheckFDT.versionAvailable) && // not if already known that update is available
157
+ ( new Date() - new Date(_appdata.updateCheckTCT.executed || 0) > 1000*3600*24*3 ||
158
+ new Date() - new Date(_appdata.updateCheckFDT.executed || 0) > 1000*3600*24*3
159
+ ) && // check every 3 days
160
+ !checkUpdatesDone // check if updatecheck has ran before because async calls below trigger beforeExit again
161
+ ) {
162
+ checkUpdatesDone = true;
144
163
  _info('Checking for updates...');
145
- selfupdate.isUpdated(_package, (error, isUpdated) => {
146
- if (!error) updateJsonFile(_paths.appdata, _appdata, {versionLastChecked: new Date(), versionIsLatest: isUpdated});
147
- _write((error || isUpdated ? 'Using latest version.' : 'New version available!') + '\n');
148
- process.exit(); // otherwise this event keeps being triggered
149
- });
164
+
165
+ // check tct version
166
+ getLatestPackageVersion({package: 'TCT', version: _package.version});
167
+
168
+ // check fdt version
169
+ getCurrentPackageVersion({package: 'FDT'})
170
+ .then(getLatestPackageVersion)
171
+ ;
150
172
  }
151
173
  });
152
174
 
@@ -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
- arr.forEach(e => {
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
+ arr.forEach(e => {
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
+ };
@@ -0,0 +1,50 @@
1
+ const util = require('util');
2
+ const exec = util.promisify(require('child_process').exec);
3
+
4
+
5
+ const packageNames = {
6
+ TCT: '@tangelo/tangelo-configuration-toolkit',
7
+ FDT: '@fontoxml/fontoxml-development-tools'
8
+ };
9
+
10
+ const updateAppdata = (data) => Object.assign(_appdata, data, {_changed: true});
11
+
12
+ const getCurrentPackageVersion = ({package}) => (
13
+ exec(`npm list -g ${packageNames[package]}`)
14
+ .then(r => ({package, version: r.stdout.match(/@([\d/.]+)/)[1]}))
15
+ .catch(e => _warn(`Failed checking current version of ${package}.`))
16
+ );
17
+
18
+ const getLatestPackageVersion = ({package, version}) => (
19
+ exec(`npm view -g ${packageNames[package]} version`)
20
+ .then(r => {
21
+ const versionAvailable = r.stdout.match(/([\d/.]+)/)[1];
22
+ if (version==versionAvailable) {
23
+ updateAppdata({[`updateCheck${package}`]: {executed: new Date()}});
24
+ _write(`Using latest version of ${package}.`);
25
+ }
26
+ else {
27
+ updateAppdata({[`updateCheck${package}`]: {executed: new Date(), versionAvailable}});
28
+ _write(`New version of ${package} available!`);
29
+ }
30
+ return {package, version, versionAvailable};
31
+ })
32
+ .catch(e => _warn(`Failed checking latest version of ${package}.`))
33
+ );
34
+
35
+ const updatePackage = ({package, version, versionAvailable}) => (
36
+ version!=versionAvailable &&
37
+ exec(`npm install -g ${packageNames[package]}`)
38
+ .then(r => {
39
+ updateAppdata({[`updateCheck${package}`]: {versionAvailable: null}});
40
+ _write(`Updated ${package} to version ${versionAvailable}.`);
41
+ })
42
+ .catch(e => _warn(`Failed updating latest version of ${package}.`))
43
+ );
44
+
45
+
46
+ module.exports = {
47
+ getCurrentPackageVersion,
48
+ getLatestPackageVersion,
49
+ updatePackage
50
+ };
@@ -78,7 +78,7 @@ const getTransformations = (config) => {
78
78
  });
79
79
  });
80
80
  } else {
81
- _write(`No transformation scenarios found in ${cf} for '${config.extracts.base}'`);
81
+ _write(`No transformation scenarios found in ${f} for '${config.extracts.base}'`);
82
82
  }
83
83
  });
84
84
  });
@@ -1,8 +1,8 @@
1
1
  const fs = require('fs-extra');
2
2
  const globby = require('globby');
3
3
  const gulp = require('gulp');
4
+ const {NodeSSH} = require('node-ssh');
4
5
  const path = require('path');
5
- const ssh = require('node-ssh');
6
6
  const through2 = require('through2');
7
7
  const {spawnSync} = require('child_process');
8
8
 
@@ -15,7 +15,7 @@ const g_print = require('gulp-print');
15
15
  const g_rename = require('gulp-simple-rename');
16
16
  const g_replace = require('../../lib/gulp-batch-replace-with-filter');
17
17
  const g_resolveIncl = require('../../lib/gulp-resolve-includes');
18
- const g_sass = require('gulp-sass');
18
+ const g_sass = require('gulp-sass')(require('sass'));
19
19
  const g_scp = require('../../lib/gulp-scp2-async');
20
20
  const g_sourcemaps = require('gulp-sourcemaps');
21
21
 
@@ -63,7 +63,7 @@ const remote = {
63
63
  process() {
64
64
  if (!this.queue[0]) return;
65
65
 
66
- const sshI = new ssh();
66
+ const sshI = new NodeSSH();
67
67
  sshI.connect(c.server.ftpConfig) // set up connection once
68
68
  .then(() => {
69
69
  this.do(sshI);
@@ -112,7 +112,9 @@ const createDeliveryPack = () => { // create install scripts if necessary, zip o
112
112
  _info('PowerShell script for database install created');
113
113
  }
114
114
 
115
- spawnSync('powershell.exe', [`Compress-Archive -Path * -DestinationPath ../${c.deliveryPackName}`], {cwd: c.server.remotedir});
115
+ const result = spawnSync('powershell.exe', [`Compress-Archive -Path * -DestinationPath ../${c.deliveryPackName}`], {cwd: c.server.remotedir});
116
+ if (result.stderr!='') {_warn(`\nLong paths may cause zip-creation to fail; Try to set a short remotedir, for example 'C:/deliveryPacks'.`);_error(`${result.stderr}\n`);}
117
+
116
118
  fs.removeSync(c.server.remotedir);
117
119
  _info(`Zipped package as: ${c.deliveryPackName}`);
118
120
  };
@@ -3,7 +3,7 @@ const fs = require('fs-extra');
3
3
  const gulp = require('gulp');
4
4
  const g_print = require('gulp-print');
5
5
  const path = require('path');
6
- const sass = require('gulp-sass');
6
+ const sass = require('gulp-sass')(require('sass'));
7
7
  const wws = require('../../lib/worker-with-spinner');
8
8
 
9
9
 
@@ -95,6 +95,16 @@ module.exports = function git (argv) {
95
95
  // Create symlinks for TDI
96
96
  ['tct b -s', 'Create TDI symlinks'],
97
97
  ]);
98
- })
98
+ }).catch((e) => {
99
+ // Show warnings for missing, expected, system environment variables
100
+ if (!process.env.GIT_SSH) {
101
+ _warn(`System environment variable 'GIT_SSH' is missing. (link to putty plink.exe)`);
102
+ }
103
+ if (!process.env.GIT_SSH_COMMAND) {
104
+ _warn(`System environment variable 'GIT_SSH_COMMAND' is missing. (link to putty plink.exe)`);
105
+ }
106
+ // continue display stack trace
107
+ throw e;
108
+ });
99
109
  }
100
110
  };
@@ -5,7 +5,8 @@ const path = require('path');
5
5
  const rif = require('replace-in-file');
6
6
 
7
7
 
8
- const getPaths = (search, filter) =>
8
+ const rifSync = (options) => rif.sync(options).filter(result => result.hasChanged).map(result => result.file);
9
+ const getPaths = (search, filter) =>
9
10
  globby
10
11
  .sync(search, {dot: true, ignore: [_paths.tdi + '/**','**/cmscustom/tdi/**']})
11
12
  .filter(p => !filter || minimatch(p, filter)
@@ -25,7 +26,7 @@ module.exports = function steps (step, dry, filter) {
25
26
  _write('Paths deleted:', paths.length);
26
27
  });
27
28
  }
28
-
29
+
29
30
  if (renamePaths) {
30
31
  renamePaths.forEach(([curpath, change]) => {
31
32
  _info(`Renaming paths: ${curpath}`);
@@ -34,7 +35,7 @@ module.exports = function steps (step, dry, filter) {
34
35
  _write('Paths renamed:', paths.length);
35
36
  });
36
37
  }
37
-
38
+
38
39
  if (replaceInFiles) {
39
40
  replaceInFiles.forEach(r => {
40
41
  _info(`Executing replacements in files: ${r.files}`);
@@ -47,9 +48,9 @@ module.exports = function steps (step, dry, filter) {
47
48
  r.to = r.fromtoPairs.map(p => p[1]);
48
49
  }
49
50
 
50
- r.files = rif.sync(r); // execute first time
51
- const filesModCount = r.files.length; // save file count
52
- for (let i=0; i<20 && !dry && r.files[0]; i++) r.files = rif.sync(r); // execute repeatedly for modified files only (with safety limit of 20)
51
+ r.files = rifSync(r); // execute first time
52
+ const filesModCount = r.files.length; // save file count
53
+ for (let i=0; i<20 && !dry && r.files[0]; i++) r.files = rifSync(r); // execute repeatedly for modified files only (with safety limit of 20)
53
54
 
54
55
  _write('Files modified:', filesModCount);
55
56
  });
@@ -14,6 +14,26 @@ const runSqlScript = (path, db, un, pw) => {
14
14
  _write('Done.\n');
15
15
  };
16
16
 
17
+ const checkLog = (logFilePath, remove=true) => {
18
+ if (fs.existsSync(logFilePath)) {
19
+ const logFile = fs.readFileSync(logFilePath).toString();
20
+ // Check for ORA- error messages
21
+ if (logFile.match(RegExp(`ORA-`, 'gm'))) {
22
+ // Select each ORA- error message and up to 6 lines before (the lines before may not contain ORA- themselves)
23
+ const errors = logFile.match(RegExp(`((?![^\n]*ORA-)[^\n]*\n){0,6}ORA-[^\n\r]*`,`gms`));
24
+ _info(`${errors.length} error(s) during SQL script:\n`)
25
+ // Print each error + lines before:
26
+ errors.forEach((e, i) => {
27
+ _info(`Tail of error ${i+1}:\n`)
28
+ _warn(`${e.trim()}\n`);
29
+ })
30
+ }
31
+ if (remove) {
32
+ // remove log file
33
+ fs.removeSync(logFilePath);
34
+ }
35
+ }
36
+ }
17
37
 
18
38
  module.exports = function sql (argv) {
19
39
 
@@ -25,8 +45,10 @@ module.exports = function sql (argv) {
25
45
  // tdi
26
46
  const dir = `${_paths.tdi}/${_isPre51 ? 'sources' : 'src'}/database/tdi/${_isPre42 ? 'install/' : ''}`;
27
47
  runSqlScript(dir + 'install.sql');
48
+ checkLog(dir + 'tdi-install.log',false);
28
49
  // custom
29
50
  runSqlScript('database/install.sql');
51
+ checkLog('database/install.log',false);
30
52
  }
31
53
 
32
54
  if (argv.configure) {
@@ -52,17 +74,20 @@ module.exports = function sql (argv) {
52
74
 
53
75
  const script = [`define l_env = ${a.pw=='tancms' ? 'dev' : 'prd'}`, 'set verify off define off'];
54
76
 
77
+ script.push(`spool install-config.log`);
55
78
  a.projects.forEach(p => {
56
79
  const dir = p.path_dbconfig ? p.path_dbconfig.join('/') : (_repoconfig.customer.dirname+'/'+p.dirname);
57
80
  script.push('prompt ', `prompt Loading configuration for: ${p.name}`);
58
81
  script.push(...globby.sync(`${dir}/*_install.sql`, {cwd}).map(s => `@${s}`));
59
82
  });
60
83
 
84
+ script.push(`spool off`);
61
85
  script.push('prompt ', 'pause Press ENTER to exit', 'exit');
62
86
 
63
87
  fs.writeFileSync(file, script.join('\n'));
64
88
  runSqlScript(file, a.db, 'tancms', a.pw);
65
89
  fs.removeSync(file);
90
+ checkLog(cwd + 'install-config.log');
66
91
  });
67
92
 
68
93
  }
@@ -75,11 +100,13 @@ module.exports = function sql (argv) {
75
100
  fs.ensureSymlinkSync(_paths.apply, dir + 'dist', 'junction');
76
101
  runSqlScript(dir + 'start.sql');
77
102
  fs.removeSync(dir + 'dist');
103
+ checkLog(dir + 'generate-config.log');
78
104
  }
79
105
 
80
106
  if (argv.remove) {
81
107
  const dir = _paths.tdi + (_isPre51 ? '/util/db-config-remover/' : '/tct/sql/remove/');
82
108
  runSqlScript(dir + 'start.sql');
109
+ checkLog(dir + 'remove-config.log');
83
110
  }
84
111
 
85
112
  };