@contentstack/cli-migration 1.5.0 → 1.5.2

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
@@ -21,7 +21,7 @@ $ npm install -g @contentstack/cli-migration
21
21
  $ csdx COMMAND
22
22
  running command...
23
23
  $ csdx (--version)
24
- @contentstack/cli-migration/1.5.0 darwin-arm64 node-v20.8.0
24
+ @contentstack/cli-migration/1.5.1 darwin-arm64 node-v20.8.0
25
25
  $ csdx --help [COMMAND]
26
26
  USAGE
27
27
  $ csdx COMMAND
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@contentstack/cli-migration",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "author": "@contentstack",
5
5
  "bugs": "https://github.com/contentstack/cli/issues",
6
6
  "dependencies": {
7
7
  "@contentstack/cli-command": "~1.2.16",
8
- "@contentstack/cli-utilities": "~1.5.12",
8
+ "@contentstack/cli-utilities": "~1.6.0",
9
9
  "async": "^3.2.4",
10
10
  "callsites": "^3.1.0",
11
11
  "cardinal": "^2.1.1",
@@ -66,4 +66,4 @@
66
66
  "cm:migration": "O-MGRTN"
67
67
  }
68
68
  }
69
- }
69
+ }
@@ -12,14 +12,19 @@ const { Parser } = require('../../../modules');
12
12
  const { ActionList } = require('../../../actions');
13
13
  const fs = require('fs');
14
14
  const chalk = require('chalk');
15
- const { printFlagDeprecation, managementSDKClient, flags, isAuthenticated } = require('@contentstack/cli-utilities');
15
+ const isEmpty = require('lodash/isEmpty');
16
+ const {
17
+ printFlagDeprecation,
18
+ managementSDKClient,
19
+ flags,
20
+ isAuthenticated,
21
+ pathValidator,
22
+ } = require('@contentstack/cli-utilities');
16
23
 
17
24
  const { ApiError, SchemaValidator, MigrationError, FieldValidator } = require('../../../validators');
18
25
 
19
26
  // Utils
20
27
  const { map: _map, constants, safePromise, errorHelper } = require('../../../utils');
21
- const { success } = require('../../../utils/logger');
22
-
23
28
  // Properties
24
29
  const { get, set, getMapInstance, resetMapInstance } = _map;
25
30
  const {
@@ -77,7 +82,7 @@ class MigrationCommand extends Command {
77
82
  let configObj = config.reduce((a, v) => {
78
83
  //NOTE: Temp code to handle only one spilt(Window absolute path issue).Need to replace with hardcoded config key
79
84
  let [key, ...value] = v.split(':');
80
- value = value?.length > 1 ? value?.join(':') : value?.join( );
85
+ value = value?.length > 1 ? value?.join(':') : value?.join();
81
86
  return { ...a, [key]: value };
82
87
  }, {});
83
88
  set('config', mapInstance, configObj);
@@ -128,11 +133,15 @@ class MigrationCommand extends Command {
128
133
  } else {
129
134
  await this.execSingleFile(filePath, mapInstance);
130
135
  }
136
+ const errLogPath = `${process.cwd()}/migration-logs`;
137
+ if (fs.existsSync(errLogPath)) {
138
+ this.log(`The log has been stored at: `, errLogPath);
139
+ }
131
140
  }
132
141
 
133
142
  async execSingleFile(filePath, mapInstance) {
134
143
  // Resolved absolute path
135
- const resolvedMigrationPath = resolve(filePath);
144
+ const resolvedMigrationPath = pathValidator(filePath);
136
145
  // User provided migration function
137
146
  const migrationFunc = require(resolvedMigrationPath);
138
147
 
@@ -154,35 +163,24 @@ class MigrationCommand extends Command {
154
163
 
155
164
  const listr = new Listr(tasks);
156
165
 
157
- await listr.run().catch((error) => {
158
- this.handleErrors(error);
159
- // When the process is child, send error message to parent
160
- if (process.send) process.send({ errorOccurred: true });
161
- });
166
+ await listr.run();
162
167
  requests.splice(0, requests.length);
163
168
  } catch (error) {
164
- // errorHandler(null, null, null, error)
165
- if (error.message) {
166
- this.log(error.message);
167
- } else if (error.errorMessage) {
168
- this.log(error.errorMessage);
169
- }else{
170
- this.log(error)
171
- }
169
+ errorHelper(error, filePath);
170
+ if (process.send) process.send({ errorOccurred: true });
172
171
  }
173
172
  }
174
173
 
175
174
  async execMultiFiles(filePath, mapInstance) {
176
175
  // Resolved absolute path
177
- const resolvedMigrationPath = resolve(filePath);
176
+ const resolvedMigrationPath = pathValidator(filePath);
178
177
  try {
179
178
  const files = fs.readdirSync(resolvedMigrationPath);
180
179
  for (const element of files) {
181
180
  const file = element;
182
181
  if (extname(file) === '.js') {
183
- success(chalk`{white Executing file:} {grey {bold ${file}}}`);
184
182
  // eslint-disable-next-line no-await-in-loop
185
- await this.execSingleFile(resolve(filePath, file), mapInstance);
183
+ await this.execSingleFile(pathValidator(resolve(filePath, file)), mapInstance);
186
184
  }
187
185
  }
188
186
  } catch (error) {
@@ -4,7 +4,7 @@
4
4
 
5
5
  const Base = require('../modules/base');
6
6
  // Utils
7
- const { map: _map, safePromise, successHandler, errorHandler, constants } = require('../utils');
7
+ const { map: _map, safePromise, successHandler, errorHandler, constants, errorHelper } = require('../utils');
8
8
  // Map methods
9
9
  const { get, getMapInstance, getDataWithAction } = _map;
10
10
  const mapInstance = getMapInstance();
@@ -23,7 +23,7 @@ class ContentTypeService {
23
23
 
24
24
  const [err, result] = await safePromise(this.stackSDKInstance.contentType(id).fetch());
25
25
  if (err) {
26
- errorHandler(id, ContentType, method, err);
26
+ errorHelper(err);
27
27
  this.base.dispatch(callsite, id, err, 'apiError');
28
28
  throw err;
29
29
  }
@@ -36,7 +36,7 @@ class ContentTypeService {
36
36
  const data = getDataWithAction(id, mapInstance, action);
37
37
  const [err, result] = await safePromise(this.stackSDKInstance.contentType().create(data));
38
38
  if (err) {
39
- errorHandler(id, ContentType, 'POST', err);
39
+ errorHelper(err);
40
40
  this.base.dispatch(callsite, id, err, 'apiError');
41
41
  throw err;
42
42
  }
@@ -51,7 +51,7 @@ class ContentTypeService {
51
51
  const method = 'PUT';
52
52
  const [err, result] = await safePromise(data.update());
53
53
  if (err) {
54
- errorHandler(data.uid, ContentType, method, err);
54
+ errorHelper(err);
55
55
  this.base.dispatch(callsite, data.uid, err, 'apiError');
56
56
  throw err;
57
57
  }
@@ -66,7 +66,7 @@ class ContentTypeService {
66
66
  const [err, result] = await safePromise(this.stackSDKInstance.contentType(id).delete());
67
67
 
68
68
  if (err) {
69
- errorHandler(id, ContentType, method, err);
69
+ errorHelper(err);
70
70
  this.base.dispatch(callsite, id, err, 'apiError');
71
71
  throw err;
72
72
  }
@@ -306,7 +306,7 @@ class ContentTypeService {
306
306
  }
307
307
 
308
308
  // Handling both the scenarios
309
- if ((found === 0) || (against && (found === 1))) {
309
+ if (found === 0 || (against && found === 1)) {
310
310
  isValid = false;
311
311
  }
312
312
 
@@ -2,9 +2,10 @@
2
2
 
3
3
  const getCallsites = require('callsites');
4
4
  const { parse, resolve } = require('path');
5
+ const { pathValidator } = require('@contentstack/cli-utilities');
5
6
 
6
7
  function getFileDirectory(path) {
7
- const parentPath = resolve(path, '../'); // Assuming that will be 2 folders up
8
+ const parentPath = pathValidator(resolve(path, '../')); // Assuming that will be 2 folders up
8
9
  return parse(parentPath).dir;
9
10
  }
10
11
 
@@ -1,8 +1,9 @@
1
1
  const { highlight } = require('cardinal');
2
2
  const { keys } = Object;
3
3
  const chalk = require('chalk');
4
- const isEmpty = require('lodash/isEmpty')
5
-
4
+ const isEmpty = require('lodash/isEmpty');
5
+ const MigrationLogger = require('./migration-logger');
6
+ const fs = require('fs');
6
7
  const { readFile } = require('./fs-helper');
7
8
  const groupBy = require('./group-by');
8
9
 
@@ -19,43 +20,86 @@ const getLineWithContext = (lines, lineNumber, context) => {
19
20
  };
20
21
  };
21
22
 
22
- module.exports = (errors) => {
23
+ function removeSpecialCharacter(str) {
24
+ return str.replace(/\u001b\[\d+m/g, '');
25
+ }
26
+
27
+ module.exports = (errors, filePath) => {
28
+ const logger = new MigrationLogger(process.cwd());
29
+
23
30
  const errorsByFile = groupBy(errors, 'file');
24
31
  const messages = [];
25
- for (const file of keys(errorsByFile)) {
26
- const fileContents = readFile(file);
27
- const highlightedCode = highlight(fileContents, { linenos: true });
28
- const lines = highlightedCode.split('\n');
29
-
30
- const fileErrorsMessage = chalk`{red Errors in ${file}}\n\n`;
31
- const errorMessages = errorsByFile[file]
32
- .map((error) => {
33
- const callsite = error.meta.callsite;
34
- const context = 2;
35
- const { before, line, after } = getLineWithContext(lines, callsite.line, context);
36
-
37
- const beforeLines = before.map((_line) => chalk`${_line}\n`);
38
- const afterLines = after.map((_line) => chalk`${_line}\n`);
39
- const highlightedLine = chalk`{bold ${line}}\n`;
40
-
41
- const formattedCode = beforeLines + highlightedLine + afterLines;
42
- if (error.payload.apiError) {
43
- return chalk`{red Line ${String(callsite.line)}:} {bold ${error.payload.apiError.message}}\n${formattedCode}`;
44
- }
45
- if (error.message) {
46
- return chalk`{red Line ${String(callsite.line)}:} {bold ${error.message}}\n${formattedCode}`;
47
- }
48
- return chalk`{red Line ${String(callsite.line)}:} {bold something went wrong here.}\n${formattedCode}`;
49
- })
50
- .join('\n');
51
-
52
- messages.push(`${fileErrorsMessage}${errorMessages}`);
53
- }
54
- if (isEmpty(messages) && errors !== undefined && isEmpty(errorsByFile)) {
55
- console.error('Migration error---', errors);
32
+ if (filePath) {
33
+ if (errors.request) {
34
+ errors.data = errors.request?.data;
35
+ delete errors.request;
36
+ }
37
+ if (errors.message) {
38
+ delete errors.message;
39
+ }
40
+ logger.log('error', { [filePath]: errors });
56
41
  } else {
57
- console.log(messages.join('\n'));
42
+ for (const file of keys(errorsByFile)) {
43
+ const errorLogs = {};
44
+ errorLogs[file] = {};
45
+ const fileContents = readFile(file);
46
+ const highlightedCode = highlight(fileContents, { linenos: true });
47
+ const lines = highlightedCode.split('\n');
48
+
49
+ const fileErrorsMessage = chalk`{red Errors in ${file}}\n\n`;
50
+ errorLogs[file].fileErrorsMessage = fileErrorsMessage.replace(/\u001b\[\d+m/g, '');
51
+ const errorMessages = errorsByFile[file]
52
+ .map((error) => {
53
+ const callsite = error.meta.callsite;
54
+ const context = 2;
55
+ let { before, line, after } = getLineWithContext(lines, callsite.line, context);
56
+
57
+ const beforeLines = before.map((_line) => chalk`${_line}\n`);
58
+ const afterLines = after.map((_line) => chalk`${_line}\n`);
59
+ const highlightedLine = chalk`{bold ${line}}\n`;
60
+
61
+ before = removeSpecialCharacter(before.join('\n'));
62
+ after = removeSpecialCharacter(after.join('\n'));
63
+ line = removeSpecialCharacter(line);
64
+ errorLogs[file].lines = { before, line, after };
65
+ if (error.request) {
66
+ error.data = error.request?.data;
67
+ delete error.request;
68
+ }
69
+ if (error.message) {
70
+ delete error.message;
71
+ }
72
+ const formattedCode = beforeLines + highlightedLine + afterLines;
73
+ if (error.payload?.apiError) {
74
+ errorLogs[file].apiError = true;
75
+ errorLogs[file].errorCode = error.payload.apiError.errorCode;
76
+ errorLogs[file].errors = error.payload.apiError.errors;
77
+ errorLogs[file].data = error.data;
78
+ }
79
+ if (error.message && !error.payload.apiError) {
80
+ errorLogs[file].apiError = false;
81
+ errorLogs[file].error = error.message;
82
+ }
83
+ })
84
+ .join('\n');
85
+
86
+ messages.push(`${fileErrorsMessage}${errorMessages}`);
87
+ logger.log('error', errorLogs);
88
+ }
89
+ if (errors?.request) {
90
+ errors.data = errors.request?.data;
91
+ delete errors.request;
92
+ }
93
+ if (errors?.message) {
94
+ delete errors.message;
95
+ }
96
+ if (isEmpty(messages) && errors !== undefined && isEmpty(errorsByFile)) {
97
+ logger.log('error', { errors: errors });
98
+ console.log(chalk`{bold.red Migration unsuccessful}`);
99
+ } else {
100
+ logger.log('error', { error: messages.join('\n') });
101
+ }
58
102
  }
59
103
  // eslint-disable-next-line
60
- console.log(chalk`{bold.red Migration unsuccessful}`);
104
+ // console.log(chalk`{bold.red Migration unsuccessful}`);
61
105
  };
@@ -2,6 +2,7 @@
2
2
 
3
3
  const { existsSync, mkdirSync, readFileSync, readFile } = require('fs');
4
4
  const path = require('path');
5
+ const { pathValidator } = require('@contentstack/cli-utilities');
5
6
 
6
7
  exports.makeDir = (dirname) => {
7
8
  !this.existsSync(dirname) && mkdirSync(dirname);
@@ -16,7 +17,7 @@ exports.readFile = (filePath) => {
16
17
 
17
18
  exports.readJSONFile = (filePath) => {
18
19
  return new Promise((resolve, reject) => {
19
- filePath = path.resolve(filePath);
20
+ filePath = pathValidator(filePath);
20
21
  readFile(filePath, 'utf-8', (error, data) => {
21
22
  if (error) {
22
23
  reject(error);
@@ -11,7 +11,6 @@ module.exports = {
11
11
  safePromise: require('./safe-promise'),
12
12
  getConfig: require('./get-config'),
13
13
  successHandler: require('./success-handler'),
14
- errorHandler: require('./error-handler'),
15
14
  getCallsite: require('./callsite'),
16
15
  errorHelper: require('./error-helper'),
17
16
  groupBy: require('./group-by'),
@@ -4,6 +4,7 @@ const { createLogger, format, transports } = require('winston');
4
4
  const { resolve, join } = require('path');
5
5
  const { slice } = Array.prototype;
6
6
  const { stringify } = JSON;
7
+ const { pathValidator } = require('@contentstack/cli-utilities');
7
8
 
8
9
  const { combine, label, printf, colorize } = format;
9
10
 
@@ -32,10 +33,10 @@ function init(logFileName) {
32
33
  // Create dir if does not exist
33
34
  makeDir(logsDir);
34
35
 
35
- const logPath = join(logsDir, logFileName + '.log');
36
+ const logPath = pathValidator(join(logsDir, logFileName + '.log'));
36
37
  const logger = createLogger({
37
38
  format: combine(colorize(), label({ label: 'Migration' }), customFormat),
38
- transports: [new transports.File({ filename: logPath }), new transports.Console()],
39
+ transports: [new transports.File({ filename: logPath })],
39
40
  });
40
41
 
41
42
  let args;
@@ -53,9 +54,9 @@ function init(logFileName) {
53
54
  logString && logger.log('warn', logString);
54
55
  },
55
56
  error: function () {
56
- args = slice.call(arguments);
57
- logString = getString(args);
58
- logString && logger.log('error', logString);
57
+ // args = slice.call(arguments);
58
+ // logString = getString(args);
59
+ // logString && logger.log('error', logString);
59
60
  },
60
61
  debug: function () {
61
62
  args = slice.call(arguments);
@@ -0,0 +1,20 @@
1
+ const winston = require('winston');
2
+ const path = require('path');
3
+ module.exports = class MigrationLogger {
4
+ constructor(filePath) {
5
+ this.filePath = path.join(filePath, 'migration-logs');
6
+ this.logger = winston.createLogger({
7
+ levels: { error: 1 },
8
+ transports: [
9
+ new winston.transports.File({
10
+ level: 'error',
11
+ filename: path.join(this.filePath, 'error.logs'),
12
+ format: winston.format.combine(winston.format.timestamp(), winston.format.json()),
13
+ }),
14
+ ],
15
+ });
16
+ }
17
+ log(level, message) {
18
+ this.logger.log('error', message);
19
+ }
20
+ };
@@ -1,21 +0,0 @@
1
- 'use strict';
2
-
3
- const { error } = require('./logger');
4
- const { errorMessageHandler } = require('./constants');
5
-
6
- module.exports = (data, type, method, err) => {
7
- if (data && type && method) {
8
- error(`Error occurred while ${errorMessageHandler[method]} ${type}: ${data}.`);
9
- }
10
-
11
- if (err.errorMessage) {
12
- error(err.errorMessage);
13
- }
14
- if (err instanceof Error && err && err.message && err.stack) {
15
- error(err.message);
16
- // error(err.stack)
17
- } else {
18
- error(err);
19
- }
20
- // throw new Error(err);
21
- };