@contentstack/cli-migration 0.1.1-beta.1
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 +69 -0
- package/oclif.manifest.json +1 -0
- package/package.json +68 -0
- package/src/actions/action-list.js +32 -0
- package/src/actions/index.js +218 -0
- package/src/commands/cm/migration.js +182 -0
- package/src/config/api-config.js +19 -0
- package/src/config/default-options.js +7 -0
- package/src/config/index.js +7 -0
- package/src/config/master-locale.js +10 -0
- package/src/modules/base.js +95 -0
- package/src/modules/content-types.js +208 -0
- package/src/modules/fields.js +304 -0
- package/src/modules/index.js +8 -0
- package/src/modules/locale.js +33 -0
- package/src/modules/migration.js +106 -0
- package/src/modules/parser.js +84 -0
- package/src/services/content-types.js +323 -0
- package/src/services/index.js +6 -0
- package/src/services/locales.js +74 -0
- package/src/utils/auto-retry.js +30 -0
- package/src/utils/callsite.js +22 -0
- package/src/utils/constants.js +219 -0
- package/src/utils/contentstack-sdk.js +71 -0
- package/src/utils/error-handler.js +21 -0
- package/src/utils/error-helper.js +58 -0
- package/src/utils/fs-helper.js +14 -0
- package/src/utils/get-batches.js +7 -0
- package/src/utils/get-config.js +13 -0
- package/src/utils/group-by.js +38 -0
- package/src/utils/index.js +21 -0
- package/src/utils/logger.js +84 -0
- package/src/utils/map.js +40 -0
- package/src/utils/object-helper.js +9 -0
- package/src/utils/request.js +95 -0
- package/src/utils/safe-promise.js +3 -0
- package/src/utils/schema-helper.js +35 -0
- package/src/utils/success-handler.js +12 -0
- package/src/validators/api-error.js +18 -0
- package/src/validators/base-validator.js +39 -0
- package/src/validators/create-content-type-validator.js +58 -0
- package/src/validators/edit-content-type-validator.js +56 -0
- package/src/validators/field-validator.js +19 -0
- package/src/validators/index.js +11 -0
- package/src/validators/migration-error.js +18 -0
- package/src/validators/schema-validator.js +21 -0
- package/src/validators/type-error.js +21 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
exports.mapObject = new Map()
|
|
4
|
+
|
|
5
|
+
exports.version = 3 // TODO: Fetch it from CMA
|
|
6
|
+
|
|
7
|
+
exports.defaultDataType = 'text'
|
|
8
|
+
|
|
9
|
+
exports.MANAGEMENT_SDK = 'MANAGEMENT_SDK'
|
|
10
|
+
exports.MANAGEMENT_SDK = 'MANAGEMENT_TOKEN'
|
|
11
|
+
exports.AUTH_TOKEN = 'AUTH_TOKEN'
|
|
12
|
+
exports.API_KEY = 'API_KEY'
|
|
13
|
+
exports.BRANCH = 'BRANCH'
|
|
14
|
+
|
|
15
|
+
exports.data_type = 'data_type'
|
|
16
|
+
exports.mandatory = 'mandatory'
|
|
17
|
+
exports._default = 'default'
|
|
18
|
+
exports.unique = 'unique'
|
|
19
|
+
exports.display_name = 'display_name'
|
|
20
|
+
exports.reference_to = 'reference_to'
|
|
21
|
+
exports.field_metadata = 'field_metadata'
|
|
22
|
+
|
|
23
|
+
exports.actions = {
|
|
24
|
+
CUSTOM_TASK: 'CUSTOM_TASK',
|
|
25
|
+
CREATE_CT: 'CREATE_CT',
|
|
26
|
+
DELETE_CT: 'DELETE_CT',
|
|
27
|
+
EDIT_CT: 'EDIT_CT',
|
|
28
|
+
LOCALES: 'LOCALES',
|
|
29
|
+
EDIT_FIELD: 'EDIT_FIELD',
|
|
30
|
+
DELETE_FIELD: 'DELETE_FIELD',
|
|
31
|
+
MOVE_FIELD: 'MOVE_FIELD',
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Http call max retry
|
|
35
|
+
exports.MAX_RETRY = 3
|
|
36
|
+
|
|
37
|
+
// This key holds the value for http objects in map
|
|
38
|
+
exports.requests = 'REQUESTS'
|
|
39
|
+
|
|
40
|
+
exports.limit = 1 // Limit for concurrent tasks executed parallely
|
|
41
|
+
|
|
42
|
+
exports.nonWritableMethods = ['GET', 'DELETE']
|
|
43
|
+
|
|
44
|
+
exports.ContentType = 'Content type'
|
|
45
|
+
exports.Entry = 'Entry'
|
|
46
|
+
|
|
47
|
+
exports.errorMessageHandler = {
|
|
48
|
+
POST: 'saving',
|
|
49
|
+
GET: 'fetching',
|
|
50
|
+
PUT: 'updating',
|
|
51
|
+
DELETE: 'deleting',
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
exports.successMessageHandler = {
|
|
55
|
+
POST: 'saved',
|
|
56
|
+
GET: 'fetched',
|
|
57
|
+
PUT: 'updated',
|
|
58
|
+
DELETE: 'deleted',
|
|
59
|
+
}
|
|
60
|
+
// map key
|
|
61
|
+
exports.actionMapper = 'actions'
|
|
62
|
+
|
|
63
|
+
exports.batchLimit = 20
|
|
64
|
+
|
|
65
|
+
exports.contentTypeProperties = ['description', 'title', 'uid', 'options', 'force', 'schema']
|
|
66
|
+
|
|
67
|
+
exports.validationAction = {
|
|
68
|
+
create: 'create',
|
|
69
|
+
edit: 'edit',
|
|
70
|
+
customTask: 'customTask',
|
|
71
|
+
transformEntries: 'transformEntries',
|
|
72
|
+
deriveLinkedEntries: 'deriveLinkedEntries',
|
|
73
|
+
transformEntriesToType: 'transformEntriesToType',
|
|
74
|
+
typeError: 'typeError',
|
|
75
|
+
apiError: 'apiError',
|
|
76
|
+
schema: 'schema',
|
|
77
|
+
__migrationError: 'migrationError',
|
|
78
|
+
field: 'field',
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
exports.transformEntriesProperties = [
|
|
82
|
+
{
|
|
83
|
+
name: 'contentType',
|
|
84
|
+
type: 'string',
|
|
85
|
+
mandatory: true,
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'from',
|
|
89
|
+
type: 'array',
|
|
90
|
+
mandatory: true,
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: 'to',
|
|
94
|
+
type: 'array',
|
|
95
|
+
mandatory: true,
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: 'shouldPublish',
|
|
99
|
+
type: 'boolean',
|
|
100
|
+
mandatory: false,
|
|
101
|
+
dependsOn: 'environments',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: 'environments',
|
|
105
|
+
type: 'array',
|
|
106
|
+
mandatory: false,
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: 'transformEntryForLocale',
|
|
110
|
+
type: 'function',
|
|
111
|
+
mandatory: true,
|
|
112
|
+
},
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
exports.deriveLinkedEntriesProperties = [
|
|
116
|
+
{
|
|
117
|
+
name: 'contentType',
|
|
118
|
+
type: 'string',
|
|
119
|
+
mandatory: true,
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: 'derivedContentType',
|
|
123
|
+
type: 'string',
|
|
124
|
+
mandatory: true,
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: 'from',
|
|
128
|
+
type: 'array',
|
|
129
|
+
mandatory: true,
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
name: 'toReferenceField',
|
|
133
|
+
type: 'string',
|
|
134
|
+
mandatory: true,
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: 'derivedFields',
|
|
138
|
+
type: 'array',
|
|
139
|
+
mandatory: true,
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: 'identityKey',
|
|
143
|
+
type: 'function',
|
|
144
|
+
mandatory: true,
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: 'shouldPublish',
|
|
148
|
+
type: 'boolean',
|
|
149
|
+
mandatory: false,
|
|
150
|
+
dependsOn: 'environments',
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: 'environments',
|
|
154
|
+
type: 'array',
|
|
155
|
+
mandatory: false,
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: 'deriveEntryForLocale',
|
|
159
|
+
type: 'function',
|
|
160
|
+
mandatory: true,
|
|
161
|
+
},
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
exports.transformEntriesToTypeProperties = [
|
|
165
|
+
{
|
|
166
|
+
name: 'sourceContentType',
|
|
167
|
+
type: 'string',
|
|
168
|
+
mandatory: true,
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: 'targetContentType',
|
|
172
|
+
type: 'string',
|
|
173
|
+
mandatory: true,
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: 'from',
|
|
177
|
+
type: 'array',
|
|
178
|
+
mandatory: true,
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
name: 'shouldPublish',
|
|
182
|
+
type: 'boolean',
|
|
183
|
+
mandatory: false,
|
|
184
|
+
dependsOn: 'environments',
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
name: 'environments',
|
|
188
|
+
type: 'array',
|
|
189
|
+
mandatory: false,
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
name: 'removeOldEntries',
|
|
193
|
+
type: 'boolean',
|
|
194
|
+
mandatory: false,
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
name: 'identityKey',
|
|
198
|
+
type: 'function',
|
|
199
|
+
mandatory: true,
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
name: 'transformEntryForLocale',
|
|
203
|
+
type: 'function',
|
|
204
|
+
mandatory: true,
|
|
205
|
+
},
|
|
206
|
+
]
|
|
207
|
+
|
|
208
|
+
exports.SDK_ACTIONS = {
|
|
209
|
+
CONTENTTYPE_GET: 'CONTENTTYPE_GET',
|
|
210
|
+
CONTENTTYPE_POST: 'CONTENTTYPE_POST',
|
|
211
|
+
CONTENTTYPE_DELETE: 'CONTENTTYPE_GET',
|
|
212
|
+
CONTENTTYPE_PUT: 'CONTENTTYPE_PUT',
|
|
213
|
+
LOCALES_GET: 'LOCALES_GET',
|
|
214
|
+
ENTRY_GET: 'ENTRY_GET',
|
|
215
|
+
ENTRY_POST: 'ENTRY_POST',
|
|
216
|
+
ENTRY_PUT: 'ENTRY_PUT',
|
|
217
|
+
ENTRY_DELETE: 'ENTRY_DELETE',
|
|
218
|
+
ENTRY_PUBLISH: 'ENTRY_PUBLISH',
|
|
219
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
/** Dependencies */
|
|
3
|
+
|
|
4
|
+
// Map helper
|
|
5
|
+
const {getMapInstance, getDataWithAction, get} = require('./map')
|
|
6
|
+
// Constants
|
|
7
|
+
const {MANAGEMENT_SDK, SDK_ACTIONS} = require('./constants')
|
|
8
|
+
// List of actions
|
|
9
|
+
const {
|
|
10
|
+
CONTENTTYPE_DELETE,
|
|
11
|
+
CONTENTTYPE_GET,
|
|
12
|
+
CONTENTTYPE_POST,
|
|
13
|
+
CONTENTTYPE_PUT,
|
|
14
|
+
LOCALES_GET,
|
|
15
|
+
ENTRY_DELETE,
|
|
16
|
+
ENTRY_GET,
|
|
17
|
+
ENTRY_POST,
|
|
18
|
+
ENTRY_PUBLISH,
|
|
19
|
+
ENTRY_PUT,
|
|
20
|
+
} = SDK_ACTIONS
|
|
21
|
+
|
|
22
|
+
module.exports = ({action, id, sdkAction}) => {
|
|
23
|
+
return async _data => {
|
|
24
|
+
_data = getData(_data, id, action)
|
|
25
|
+
|
|
26
|
+
const mapInstance = getMapInstance()
|
|
27
|
+
const managementSdk = get(MANAGEMENT_SDK, mapInstance)
|
|
28
|
+
const {stack} = managementSdk
|
|
29
|
+
|
|
30
|
+
let response
|
|
31
|
+
|
|
32
|
+
switch (sdkAction) {
|
|
33
|
+
case CONTENTTYPE_GET:
|
|
34
|
+
response = await stack.contentType(id).fetch()
|
|
35
|
+
return response
|
|
36
|
+
case CONTENTTYPE_POST:
|
|
37
|
+
response = await stack.contentType().create(_data)
|
|
38
|
+
return response
|
|
39
|
+
case CONTENTTYPE_PUT:
|
|
40
|
+
// const contentType = await stack.contentType(id).fetch();
|
|
41
|
+
response = await stack.contentType(_data).update()
|
|
42
|
+
return response
|
|
43
|
+
case CONTENTTYPE_DELETE:
|
|
44
|
+
response = await stack.contentType(id).delete()
|
|
45
|
+
return response
|
|
46
|
+
case LOCALES_GET:
|
|
47
|
+
return response
|
|
48
|
+
case ENTRY_GET:
|
|
49
|
+
return response
|
|
50
|
+
case ENTRY_POST:
|
|
51
|
+
return response
|
|
52
|
+
case ENTRY_PUBLISH:
|
|
53
|
+
return response
|
|
54
|
+
case ENTRY_DELETE:
|
|
55
|
+
return response
|
|
56
|
+
case ENTRY_PUT:
|
|
57
|
+
return response
|
|
58
|
+
default:
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getData(_data, id, action) {
|
|
64
|
+
let mapInstance = getMapInstance()
|
|
65
|
+
|
|
66
|
+
let data = _data ? _data : getDataWithAction(id, mapInstance, action)
|
|
67
|
+
|
|
68
|
+
// return stringify(data);
|
|
69
|
+
return data
|
|
70
|
+
}
|
|
71
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
|
|
2
|
+
const {highlight} = require('cardinal')
|
|
3
|
+
const {keys} = Object
|
|
4
|
+
const chalk = require('chalk')
|
|
5
|
+
|
|
6
|
+
const {readFile} = require('./fs-helper')
|
|
7
|
+
const groupBy = require('./group-by')
|
|
8
|
+
|
|
9
|
+
const getLineWithContext = (lines, lineNumber, context) => {
|
|
10
|
+
const line = (lineNumber - 1)
|
|
11
|
+
|
|
12
|
+
const firstLine = (line > context) ? (line - context) : 0
|
|
13
|
+
const lastLine = (line + context) < lines.length ? line + context : lines.length
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
before: lines.slice(firstLine, line),
|
|
17
|
+
line: lines[line],
|
|
18
|
+
after: lines.slice(line + 1, lastLine + 1),
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = errors => {
|
|
23
|
+
const errorsByFile = groupBy(errors, 'file')
|
|
24
|
+
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].map(error => {
|
|
32
|
+
const callsite = error.meta.callsite
|
|
33
|
+
const context = 2
|
|
34
|
+
const {before, line, after} = getLineWithContext(lines, callsite.line, context)
|
|
35
|
+
|
|
36
|
+
const beforeLines = before.map(line => chalk`${line}\n`)
|
|
37
|
+
const afterLines = after.map(line => chalk`${line}\n`)
|
|
38
|
+
const highlightedLine = chalk`{bold ${line}}\n`
|
|
39
|
+
|
|
40
|
+
const formattedCode = beforeLines + highlightedLine + afterLines
|
|
41
|
+
if (error.payload.apiError) {
|
|
42
|
+
return chalk`{red Line ${String(callsite.line)}:} {bold ${error.payload.apiError.message}}\n${formattedCode}`
|
|
43
|
+
}
|
|
44
|
+
if (error.message) {
|
|
45
|
+
return chalk`{red Line ${String(callsite.line)}:} {bold ${error.message}}\n${formattedCode}`
|
|
46
|
+
}
|
|
47
|
+
return chalk`{red Line ${String(callsite.line)}:} {bold something went wrong here.}\n${formattedCode}`
|
|
48
|
+
}).join('\n')
|
|
49
|
+
|
|
50
|
+
messages.push(`${fileErrorsMessage}${errorMessages}`)
|
|
51
|
+
}
|
|
52
|
+
// eslint-disable-next-line
|
|
53
|
+
// console.error(chalk`{red.bold Validation failed}\n\n`);
|
|
54
|
+
// eslint-disable-next-line
|
|
55
|
+
console.log(messages.join('\n'));
|
|
56
|
+
// eslint-disable-next-line
|
|
57
|
+
console.log(chalk`{bold.red Migration unsuccessful}`);
|
|
58
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {existsSync, mkdirSync, readFileSync} = require('fs')
|
|
4
|
+
|
|
5
|
+
exports.makeDir = dirname => {
|
|
6
|
+
!this.existsSync(dirname) && mkdirSync(dirname)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
exports.existsSync = filePath => existsSync(filePath)
|
|
10
|
+
|
|
11
|
+
exports.readFile = filePath => {
|
|
12
|
+
if (!existsSync(filePath)) throw new Error('File does not exist')
|
|
13
|
+
return readFileSync(filePath, 'utf-8')
|
|
14
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {apiConfig} = require('../config')
|
|
4
|
+
|
|
5
|
+
module.exports = ({method, path, sdkAction}) => {
|
|
6
|
+
return {
|
|
7
|
+
...apiConfig,
|
|
8
|
+
path: path ? `${apiConfig.version}${path}` : apiConfig.version,
|
|
9
|
+
method,
|
|
10
|
+
headers: {...apiConfig.headers},
|
|
11
|
+
sdkAction,
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
module.exports = function groupBy(data, field, i = 0, finalObj = {}, originalArray = []) {
|
|
4
|
+
if (!data) return finalObj
|
|
5
|
+
|
|
6
|
+
if (Array.isArray(data)) {
|
|
7
|
+
groupBy(data[i], field, 0, finalObj, data)
|
|
8
|
+
} else if (field in data) {
|
|
9
|
+
let dataField = data[field]
|
|
10
|
+
if (dataField in finalObj) {
|
|
11
|
+
finalObj[dataField].push(originalArray[i])
|
|
12
|
+
} else {
|
|
13
|
+
finalObj[dataField] = []
|
|
14
|
+
finalObj[dataField].push(originalArray[i])
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
i++
|
|
18
|
+
|
|
19
|
+
// Breaks when i has been incremented more than length of original array
|
|
20
|
+
if (i !== 0 && i >= originalArray.length) return finalObj
|
|
21
|
+
/**
|
|
22
|
+
* After the field is found only then increment i and inspect next item
|
|
23
|
+
* This will restrict iterating through array just to the length of array
|
|
24
|
+
*/
|
|
25
|
+
groupBy(originalArray[i], field, i, finalObj, originalArray)
|
|
26
|
+
} else {
|
|
27
|
+
for (let key in data) {
|
|
28
|
+
if (key) {
|
|
29
|
+
let dataKey = data[key]
|
|
30
|
+
if (!Array.isArray(dataKey) && typeof dataKey === 'object') {
|
|
31
|
+
groupBy(dataKey, field, i, finalObj, originalArray)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return finalObj
|
|
38
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
map: require('./map'),
|
|
5
|
+
constants: require('./constants'),
|
|
6
|
+
schemaHelper: require('./schema-helper'),
|
|
7
|
+
objectHelper: require('./object-helper'),
|
|
8
|
+
fsHelper: require('./fs-helper'),
|
|
9
|
+
logger: require('./logger'),
|
|
10
|
+
https: require('./request'),
|
|
11
|
+
safePromise: require('./safe-promise'),
|
|
12
|
+
getConfig: require('./get-config'),
|
|
13
|
+
successHandler: require('./success-handler'),
|
|
14
|
+
errorHandler: require('./error-handler'),
|
|
15
|
+
getCallsite: require('./callsite'),
|
|
16
|
+
errorHelper: require('./error-helper'),
|
|
17
|
+
groupBy: require('./group-by'),
|
|
18
|
+
getBatches: require('./get-batches'),
|
|
19
|
+
autoRetry: require('./auto-retry'),
|
|
20
|
+
contentstackSdk: require('./contentstack-sdk'),
|
|
21
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {createLogger, format, transports} = require('winston')
|
|
4
|
+
const {resolve, join} = require('path')
|
|
5
|
+
const {slice} = Array.prototype
|
|
6
|
+
const {stringify} = JSON
|
|
7
|
+
|
|
8
|
+
const {combine, label, printf, colorize} = format
|
|
9
|
+
|
|
10
|
+
// FS helper
|
|
11
|
+
const {makeDir} = require('./fs-helper')
|
|
12
|
+
|
|
13
|
+
const {NODE_ENV} = process.env
|
|
14
|
+
|
|
15
|
+
function getString(args) {
|
|
16
|
+
let str = ''
|
|
17
|
+
if (args && args.length > 0) {
|
|
18
|
+
str = args.map(item =>
|
|
19
|
+
item && typeof item === 'object' ?
|
|
20
|
+
stringify(item) :
|
|
21
|
+
item
|
|
22
|
+
)
|
|
23
|
+
.join(' ')
|
|
24
|
+
.trim()
|
|
25
|
+
}
|
|
26
|
+
return str
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const customFormat = printf(({level, message}) => {
|
|
30
|
+
return `${level}: ${message}`
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
function init(logFileName) {
|
|
34
|
+
const logsDir = resolve('logs')
|
|
35
|
+
// Create dir if does not exist
|
|
36
|
+
makeDir(logsDir)
|
|
37
|
+
|
|
38
|
+
const logPath = join(logsDir, logFileName + '.log')
|
|
39
|
+
const logger = createLogger({
|
|
40
|
+
format: combine(
|
|
41
|
+
colorize(),
|
|
42
|
+
label({label: 'Migration'}),
|
|
43
|
+
customFormat
|
|
44
|
+
),
|
|
45
|
+
transports: [
|
|
46
|
+
new transports.File({filename: logPath}),
|
|
47
|
+
new transports.Console(),
|
|
48
|
+
],
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
let args
|
|
52
|
+
let logString
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
log: function () {
|
|
56
|
+
args = slice.call(arguments)
|
|
57
|
+
logString = getString(args)
|
|
58
|
+
logString && logger.log('info', logString)
|
|
59
|
+
},
|
|
60
|
+
warn: function () {
|
|
61
|
+
args = slice.call(arguments)
|
|
62
|
+
logString = getString(args)
|
|
63
|
+
logString && logger.log('warn', logString)
|
|
64
|
+
},
|
|
65
|
+
error: function () {
|
|
66
|
+
args = slice.call(arguments)
|
|
67
|
+
logString = getString(args)
|
|
68
|
+
logString && logger.log('error', logString)
|
|
69
|
+
},
|
|
70
|
+
debug: function () {
|
|
71
|
+
args = slice.call(arguments)
|
|
72
|
+
logString = getString(args)
|
|
73
|
+
logString && logger.log('debug', logString)
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
exports.success = init('success').log
|
|
79
|
+
if (NODE_ENV === 'test') {
|
|
80
|
+
exports.error = init('warn').warn
|
|
81
|
+
} else {
|
|
82
|
+
exports.error = init('error').error
|
|
83
|
+
}
|
|
84
|
+
exports.warn = init('warn').warn
|
package/src/utils/map.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {mapObject, actionMapper, requests} = require('./constants')
|
|
4
|
+
|
|
5
|
+
exports.getMapInstance = () => {
|
|
6
|
+
return mapObject
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
exports.get = (id, mapInstance, data = []) => {
|
|
10
|
+
// Create key if does not exist
|
|
11
|
+
let __data = mapInstance.get(id)
|
|
12
|
+
|
|
13
|
+
!__data && (
|
|
14
|
+
mapInstance.set(id, data),
|
|
15
|
+
__data = mapInstance.get(id)
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
return __data
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
exports.set = (id, mapInstance, data) => {
|
|
22
|
+
return mapInstance.set(id, data)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
exports.remove = (id, mapInstance) => {
|
|
26
|
+
return mapInstance.delete(id)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
exports.getDataWithAction = (id, mapInstance, action) => {
|
|
30
|
+
let data = this.get(id, mapInstance)
|
|
31
|
+
data = data[action]
|
|
32
|
+
return data
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
exports.resetMapInstance = mapInstance => {
|
|
36
|
+
this.set(actionMapper, mapInstance, [])
|
|
37
|
+
this.set(requests, mapInstance, [])
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
exports.delete = () => { }
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// Dependencies
|
|
4
|
+
const {request} = require('https')
|
|
5
|
+
const {stringify, parse} = JSON
|
|
6
|
+
|
|
7
|
+
// Map helper
|
|
8
|
+
const {getMapInstance, getDataWithAction} = require('./map')
|
|
9
|
+
|
|
10
|
+
// constants
|
|
11
|
+
const {actions, nonWritableMethods} = require('./constants')
|
|
12
|
+
|
|
13
|
+
// Properties
|
|
14
|
+
const {DELETE_CT} = actions
|
|
15
|
+
|
|
16
|
+
module.exports = ({
|
|
17
|
+
hostname,
|
|
18
|
+
path,
|
|
19
|
+
headers,
|
|
20
|
+
method,
|
|
21
|
+
id,
|
|
22
|
+
action,
|
|
23
|
+
}) => {
|
|
24
|
+
let options = {
|
|
25
|
+
hostname,
|
|
26
|
+
path,
|
|
27
|
+
headers,
|
|
28
|
+
method,
|
|
29
|
+
id,
|
|
30
|
+
action,
|
|
31
|
+
}
|
|
32
|
+
return _data => {
|
|
33
|
+
// get data here using id and action
|
|
34
|
+
let data = getData(_data, id, action, method)
|
|
35
|
+
// Special handling for non writable methods
|
|
36
|
+
options = getNewOptions(options, data, action, method)
|
|
37
|
+
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
const req = request(options, res => {
|
|
40
|
+
let response = ''
|
|
41
|
+
|
|
42
|
+
res.on('data', _res => {
|
|
43
|
+
response += _res.toString()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
res.on('end', () => {
|
|
47
|
+
try {
|
|
48
|
+
response = parse(response)
|
|
49
|
+
resolve(response)
|
|
50
|
+
} catch (err) {
|
|
51
|
+
reject('Error while parsing response!')
|
|
52
|
+
// throw new Error('Error while parsing response!');
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
req.on('error', err => {
|
|
58
|
+
reject(err)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
!nonWritableMethods.includes(method) && req.write(data)
|
|
62
|
+
req.end()
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function getData(_data, id, action, method) {
|
|
68
|
+
if (method === 'GET') return
|
|
69
|
+
// if (!nonWritableMethods.includes(method)) {
|
|
70
|
+
let mapInstance = getMapInstance()
|
|
71
|
+
|
|
72
|
+
let data = _data ? _data : getDataWithAction(id, mapInstance, action)
|
|
73
|
+
return stringify(data)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function getNewOptions(options, data, action, method) {
|
|
77
|
+
// Special handling for delete method
|
|
78
|
+
if (action === DELETE_CT) {
|
|
79
|
+
try {
|
|
80
|
+
data = parse(data)
|
|
81
|
+
} catch (err) {
|
|
82
|
+
throw 'Error while parsing data for delete operation'
|
|
83
|
+
}
|
|
84
|
+
options.path = `${options.path}?force=${data.content_type.force}`
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (!nonWritableMethods.includes(method)) {
|
|
88
|
+
options.headers['Content-Length'] = data.length
|
|
89
|
+
} else {
|
|
90
|
+
delete options.headers['Content-Type']
|
|
91
|
+
delete options.headers['Content-Length']
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return options
|
|
95
|
+
}
|