contentful-import 9.0.21 → 9.2.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/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1277 -124
- package/dist/index.mjs +1308 -0
- package/package.json +34 -20
- package/dist/parseOptions.js +0 -94
- package/dist/tasks/get-destination-data.js +0 -155
- package/dist/tasks/init-client.js +0 -25
- package/dist/tasks/push-to-space/assets.js +0 -83
- package/dist/tasks/push-to-space/creation.js +0 -227
- package/dist/tasks/push-to-space/publishing.js +0 -100
- package/dist/tasks/push-to-space/push-to-space.js +0 -346
- package/dist/transform/transform-space.js +0 -36
- package/dist/transform/transformers.js +0 -75
- package/dist/usageParams.js +0 -76
- package/dist/utils/headers.js +0 -45
- package/dist/utils/schema.js +0 -96
- package/dist/utils/sort-entries.js +0 -93
- package/dist/utils/sort-locales.js +0 -42
- package/dist/utils/validations.js +0 -57
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.createEntities = createEntities;
|
|
7
|
-
exports.createEntries = createEntries;
|
|
8
|
-
exports.createLocales = createLocales;
|
|
9
|
-
var _collection = require("lodash/collection");
|
|
10
|
-
var _object = require("lodash/object");
|
|
11
|
-
var _getEntityName = _interopRequireDefault(require("contentful-batch-libs/dist/get-entity-name"));
|
|
12
|
-
var _logging = require("contentful-batch-libs/dist/logging");
|
|
13
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
14
|
-
/**
|
|
15
|
-
* Creates a list of entities
|
|
16
|
-
* Applies to all entities except Entries, as the CMA API for those is slightly different
|
|
17
|
-
* See handleCreationErrors for details on what errors reject the promise or not.
|
|
18
|
-
*/
|
|
19
|
-
function createEntities({
|
|
20
|
-
context,
|
|
21
|
-
entities,
|
|
22
|
-
destinationEntitiesById,
|
|
23
|
-
requestQueue
|
|
24
|
-
}) {
|
|
25
|
-
return createEntitiesWithConcurrency({
|
|
26
|
-
context,
|
|
27
|
-
entities,
|
|
28
|
-
destinationEntitiesById,
|
|
29
|
-
requestQueue
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// TODO
|
|
34
|
-
// Locales need to be created in series
|
|
35
|
-
function createLocales({
|
|
36
|
-
context,
|
|
37
|
-
entities,
|
|
38
|
-
destinationEntitiesById,
|
|
39
|
-
requestQueue
|
|
40
|
-
}) {
|
|
41
|
-
return createEntitiesInSequence({
|
|
42
|
-
context,
|
|
43
|
-
entities,
|
|
44
|
-
destinationEntitiesById,
|
|
45
|
-
requestQueue
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
async function createEntitiesWithConcurrency({
|
|
49
|
-
context,
|
|
50
|
-
entities,
|
|
51
|
-
destinationEntitiesById,
|
|
52
|
-
requestQueue
|
|
53
|
-
}) {
|
|
54
|
-
const pendingCreatedEntities = entities.map(entity => {
|
|
55
|
-
const destinationEntity = getDestinationEntityForSourceEntity(destinationEntitiesById, entity.transformed);
|
|
56
|
-
const operation = destinationEntity ? 'update' : 'create';
|
|
57
|
-
return requestQueue.add(async () => {
|
|
58
|
-
try {
|
|
59
|
-
const createdEntity = await (destinationEntity ? updateDestinationWithSourceData(destinationEntity, entity.transformed) : createInDestination(context, entity.transformed));
|
|
60
|
-
creationSuccessNotifier(operation, createdEntity);
|
|
61
|
-
return createdEntity;
|
|
62
|
-
} catch (err) {
|
|
63
|
-
return handleCreationErrors(entity, err);
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
const createdEntities = await Promise.all(pendingCreatedEntities);
|
|
68
|
-
|
|
69
|
-
// Filter null values in case of errors
|
|
70
|
-
return createdEntities.filter(entity => entity);
|
|
71
|
-
}
|
|
72
|
-
async function createEntitiesInSequence({
|
|
73
|
-
context,
|
|
74
|
-
entities,
|
|
75
|
-
destinationEntitiesById,
|
|
76
|
-
requestQueue
|
|
77
|
-
}) {
|
|
78
|
-
const createdEntities = [];
|
|
79
|
-
for (const entity of entities) {
|
|
80
|
-
const destinationEntity = getDestinationEntityForSourceEntity(destinationEntitiesById, entity.transformed);
|
|
81
|
-
const operation = destinationEntity ? 'update' : 'create';
|
|
82
|
-
try {
|
|
83
|
-
// Even though we run things in sequence here,
|
|
84
|
-
// we still want to go through the normal rate limiting queue
|
|
85
|
-
const createdEntity = await requestQueue.add(async () => {
|
|
86
|
-
const createdOrUpdatedEntity = await (destinationEntity ? updateDestinationWithSourceData(destinationEntity, entity.transformed) : createInDestination(context, entity.transformed));
|
|
87
|
-
return createdOrUpdatedEntity;
|
|
88
|
-
});
|
|
89
|
-
creationSuccessNotifier(operation, createdEntity);
|
|
90
|
-
createdEntities.push(createdEntity);
|
|
91
|
-
} catch (err) {
|
|
92
|
-
const maybeSubstituteEntity = handleCreationErrors(entity, err);
|
|
93
|
-
if (maybeSubstituteEntity) {
|
|
94
|
-
createdEntities.push(maybeSubstituteEntity);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return createdEntities;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Creates a list of entries
|
|
103
|
-
*/
|
|
104
|
-
async function createEntries({
|
|
105
|
-
context,
|
|
106
|
-
entities,
|
|
107
|
-
destinationEntitiesById,
|
|
108
|
-
requestQueue
|
|
109
|
-
}) {
|
|
110
|
-
const createdEntries = await Promise.all(entities.map(entry => {
|
|
111
|
-
return createEntry({
|
|
112
|
-
entry,
|
|
113
|
-
target: context.target,
|
|
114
|
-
skipContentModel: context.skipContentModel,
|
|
115
|
-
destinationEntitiesById,
|
|
116
|
-
requestQueue
|
|
117
|
-
});
|
|
118
|
-
}));
|
|
119
|
-
return createdEntries.filter(entry => entry);
|
|
120
|
-
}
|
|
121
|
-
async function createEntry({
|
|
122
|
-
entry,
|
|
123
|
-
target,
|
|
124
|
-
skipContentModel,
|
|
125
|
-
destinationEntitiesById,
|
|
126
|
-
requestQueue
|
|
127
|
-
}) {
|
|
128
|
-
const contentTypeId = entry.original.sys.contentType.sys.id;
|
|
129
|
-
const destinationEntry = getDestinationEntityForSourceEntity(destinationEntitiesById, entry.transformed);
|
|
130
|
-
const operation = destinationEntry ? 'update' : 'create';
|
|
131
|
-
try {
|
|
132
|
-
const createdOrUpdatedEntry = await requestQueue.add(() => {
|
|
133
|
-
return destinationEntry ? updateDestinationWithSourceData(destinationEntry, entry.transformed) : createEntryInDestination(target, contentTypeId, entry.transformed);
|
|
134
|
-
});
|
|
135
|
-
creationSuccessNotifier(operation, createdOrUpdatedEntry);
|
|
136
|
-
return createdOrUpdatedEntry;
|
|
137
|
-
} catch (err) {
|
|
138
|
-
/* If a field doesn't exist, it means it has been removed from the content types
|
|
139
|
-
* In that case, the field is removed from the entry, and creation is attempted again.
|
|
140
|
-
*/
|
|
141
|
-
if (skipContentModel && err.name === 'UnknownField') {
|
|
142
|
-
const errors = (0, _object.get)(JSON.parse(err.message), 'details.errors');
|
|
143
|
-
entry.transformed.fields = cleanupUnknownFields(entry.transformed.fields, errors);
|
|
144
|
-
return createEntry({
|
|
145
|
-
entry,
|
|
146
|
-
target,
|
|
147
|
-
skipContentModel,
|
|
148
|
-
destinationEntitiesById,
|
|
149
|
-
requestQueue
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
err.entity = entry;
|
|
153
|
-
_logging.logEmitter.emit('error', err);
|
|
154
|
-
|
|
155
|
-
// No need to pass this entry down to publishing if it wasn't created
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
function updateDestinationWithSourceData(destinationEntity, sourceEntity) {
|
|
160
|
-
const plainData = getPlainData(sourceEntity);
|
|
161
|
-
(0, _object.assign)(destinationEntity, plainData);
|
|
162
|
-
return destinationEntity.update();
|
|
163
|
-
}
|
|
164
|
-
function createInDestination(context, sourceEntity) {
|
|
165
|
-
const {
|
|
166
|
-
type,
|
|
167
|
-
target
|
|
168
|
-
} = context;
|
|
169
|
-
if (type === 'Tag') {
|
|
170
|
-
// tags are created with a different signature
|
|
171
|
-
return createTagInDestination(context, sourceEntity);
|
|
172
|
-
}
|
|
173
|
-
const id = (0, _object.get)(sourceEntity, 'sys.id');
|
|
174
|
-
const plainData = getPlainData(sourceEntity);
|
|
175
|
-
return id ? target[`create${type}WithId`](id, plainData) : target[`create${type}`](plainData);
|
|
176
|
-
}
|
|
177
|
-
function createEntryInDestination(space, contentTypeId, sourceEntity) {
|
|
178
|
-
const id = sourceEntity.sys.id;
|
|
179
|
-
const plainData = getPlainData(sourceEntity);
|
|
180
|
-
return id ? space.createEntryWithId(contentTypeId, id, plainData) : space.createEntry(contentTypeId, plainData);
|
|
181
|
-
}
|
|
182
|
-
function createTagInDestination(context, sourceEntity) {
|
|
183
|
-
const id = sourceEntity.sys.id;
|
|
184
|
-
const visibility = sourceEntity.sys.visibility || 'private';
|
|
185
|
-
const name = sourceEntity.name;
|
|
186
|
-
return context.target.createTag(id, name, visibility);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Handles entity creation errors.
|
|
191
|
-
* If the error is a VersionMismatch the error is thrown and a message is returned
|
|
192
|
-
* instructing the user on what this situation probably means.
|
|
193
|
-
*/
|
|
194
|
-
function handleCreationErrors(entity, err) {
|
|
195
|
-
// Handle the case where a locale already exists and skip it
|
|
196
|
-
if ((0, _object.get)(err, 'error.sys.id') === 'ValidationFailed') {
|
|
197
|
-
const errors = (0, _object.get)(err, 'error.details.errors');
|
|
198
|
-
if (errors && errors.length > 0 && errors[0].name === 'taken') {
|
|
199
|
-
return entity;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
err.entity = entity.original;
|
|
203
|
-
_logging.logEmitter.emit('error', err);
|
|
204
|
-
|
|
205
|
-
// No need to pass this entity down to publishing if it wasn't created
|
|
206
|
-
return null;
|
|
207
|
-
}
|
|
208
|
-
function cleanupUnknownFields(fields, errors) {
|
|
209
|
-
return (0, _object.omitBy)(fields, (field, fieldId) => {
|
|
210
|
-
return (0, _collection.find)(errors, error => {
|
|
211
|
-
const [, errorFieldId] = error.path;
|
|
212
|
-
return error.name === 'unknown' && errorFieldId === fieldId;
|
|
213
|
-
});
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
function getDestinationEntityForSourceEntity(destinationEntitiesById, sourceEntity) {
|
|
217
|
-
return destinationEntitiesById.get((0, _object.get)(sourceEntity, 'sys.id')) || null;
|
|
218
|
-
}
|
|
219
|
-
function creationSuccessNotifier(method, createdEntity) {
|
|
220
|
-
const verb = method[0].toUpperCase() + method.substr(1, method.length) + 'd';
|
|
221
|
-
_logging.logEmitter.emit('info', `${verb} ${createdEntity.sys.type} ${(0, _getEntityName.default)(createdEntity)}`);
|
|
222
|
-
return createdEntity;
|
|
223
|
-
}
|
|
224
|
-
function getPlainData(entity) {
|
|
225
|
-
const data = entity.toPlainObject ? entity.toPlainObject() : entity;
|
|
226
|
-
return (0, _object.omit)(data, 'sys');
|
|
227
|
-
}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.archiveEntities = archiveEntities;
|
|
7
|
-
exports.publishEntities = publishEntities;
|
|
8
|
-
var _getEntityName = _interopRequireDefault(require("contentful-batch-libs/dist/get-entity-name"));
|
|
9
|
-
var _logging = require("contentful-batch-libs/dist/logging");
|
|
10
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
|
-
/**
|
|
12
|
-
* Publish a list of entities.
|
|
13
|
-
* Does not return a rejected promise in the case of an error, pushing it
|
|
14
|
-
* to an error buffer instead.
|
|
15
|
-
*/
|
|
16
|
-
async function publishEntities({
|
|
17
|
-
entities,
|
|
18
|
-
requestQueue
|
|
19
|
-
}) {
|
|
20
|
-
const entitiesToPublish = entities.filter(entity => {
|
|
21
|
-
if (!entity || !entity.publish) {
|
|
22
|
-
_logging.logEmitter.emit('warning', `Unable to publish ${(0, _getEntityName.default)(entity)}`);
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
return true;
|
|
26
|
-
});
|
|
27
|
-
if (entitiesToPublish.length === 0) {
|
|
28
|
-
_logging.logEmitter.emit('info', 'Skipping publishing since zero valid entities passed');
|
|
29
|
-
return [];
|
|
30
|
-
}
|
|
31
|
-
const entity = entities[0].original || entities[0];
|
|
32
|
-
const type = entity.sys.type || 'unknown type';
|
|
33
|
-
_logging.logEmitter.emit('info', `Publishing ${entities.length} ${type}s`);
|
|
34
|
-
const result = await runQueue(entitiesToPublish, [], requestQueue);
|
|
35
|
-
_logging.logEmitter.emit('info', `Successfully published ${result.length} ${type}s`);
|
|
36
|
-
return result;
|
|
37
|
-
}
|
|
38
|
-
async function archiveEntities({
|
|
39
|
-
entities,
|
|
40
|
-
requestQueue
|
|
41
|
-
}) {
|
|
42
|
-
const entitiesToArchive = entities.filter(entity => {
|
|
43
|
-
if (!entity || !entity.archive) {
|
|
44
|
-
_logging.logEmitter.emit('warning', `Unable to archive ${(0, _getEntityName.default)(entity)}`);
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
return true;
|
|
48
|
-
});
|
|
49
|
-
if (entitiesToArchive.length === 0) {
|
|
50
|
-
_logging.logEmitter.emit('info', 'Skipping archiving since zero valid entities passed');
|
|
51
|
-
return [];
|
|
52
|
-
}
|
|
53
|
-
const entity = entities[0].original || entities[0];
|
|
54
|
-
const type = entity.sys.type || 'unknown type';
|
|
55
|
-
_logging.logEmitter.emit('info', `Archiving ${entities.length} ${type}s`);
|
|
56
|
-
const pendingArchivedEntities = entitiesToArchive.map(entity => {
|
|
57
|
-
return requestQueue.add(async () => {
|
|
58
|
-
try {
|
|
59
|
-
const archivedEntity = await entity.archive();
|
|
60
|
-
return archivedEntity;
|
|
61
|
-
} catch (err) {
|
|
62
|
-
err.entity = entity;
|
|
63
|
-
_logging.logEmitter.emit('error', err);
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
const allPossiblyArchivedEntities = await Promise.all(pendingArchivedEntities);
|
|
69
|
-
const allArchivedEntities = allPossiblyArchivedEntities.filter(entity => entity);
|
|
70
|
-
_logging.logEmitter.emit('info', `Successfully archived ${allArchivedEntities.length} ${type}s`);
|
|
71
|
-
return allArchivedEntities;
|
|
72
|
-
}
|
|
73
|
-
async function runQueue(queue, result = [], requestQueue) {
|
|
74
|
-
const publishedEntities = [];
|
|
75
|
-
for (const entity of queue) {
|
|
76
|
-
_logging.logEmitter.emit('info', `Publishing ${entity.sys.type} ${(0, _getEntityName.default)(entity)}`);
|
|
77
|
-
try {
|
|
78
|
-
const publishedEntity = await requestQueue.add(() => entity.publish());
|
|
79
|
-
publishedEntities.push(publishedEntity);
|
|
80
|
-
} catch (err) {
|
|
81
|
-
err.entity = entity;
|
|
82
|
-
_logging.logEmitter.emit('error', err);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
result = [...result, ...publishedEntities];
|
|
86
|
-
const publishedEntityIds = new Set(publishedEntities.map(entity => entity.sys.id));
|
|
87
|
-
const unpublishedEntities = queue.filter(entity => !publishedEntityIds.has(entity.sys.id));
|
|
88
|
-
if (unpublishedEntities.length > 0) {
|
|
89
|
-
if (queue.length === unpublishedEntities.length) {
|
|
90
|
-
// Fail when queue could not publish at least one item
|
|
91
|
-
const unpublishedEntityNames = unpublishedEntities.map(_getEntityName.default).join(', ');
|
|
92
|
-
_logging.logEmitter.emit('error', `Could not publish the following entities: ${unpublishedEntityNames}`);
|
|
93
|
-
} else {
|
|
94
|
-
// Rerun queue with unpublished entities
|
|
95
|
-
return runQueue(unpublishedEntities, result, requestQueue);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
// Return only published entities + last result
|
|
99
|
-
return result;
|
|
100
|
-
}
|
|
@@ -1,346 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = pushToSpace;
|
|
7
|
-
var _listr = _interopRequireDefault(require("listr"));
|
|
8
|
-
var _listrVerboseRenderer = _interopRequireDefault(require("listr-verbose-renderer"));
|
|
9
|
-
var _logging = require("contentful-batch-libs/dist/logging");
|
|
10
|
-
var _listr2 = require("contentful-batch-libs/dist/listr");
|
|
11
|
-
var assets = _interopRequireWildcard(require("./assets"));
|
|
12
|
-
var creation = _interopRequireWildcard(require("./creation"));
|
|
13
|
-
var publishing = _interopRequireWildcard(require("./publishing"));
|
|
14
|
-
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
15
|
-
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
16
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
17
|
-
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
18
|
-
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
19
|
-
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
20
|
-
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
|
21
|
-
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
|
22
|
-
const DEFAULT_CONTENT_STRUCTURE = {
|
|
23
|
-
entries: [],
|
|
24
|
-
assets: [],
|
|
25
|
-
contentTypes: [],
|
|
26
|
-
tags: [],
|
|
27
|
-
locales: [],
|
|
28
|
-
webhooks: [],
|
|
29
|
-
editorInterfaces: []
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Pushes all changes to a given space. Handles (un)publishing
|
|
34
|
-
* as well as delays after creation and before publishing.
|
|
35
|
-
*
|
|
36
|
-
* Creates everything in the right order so that a content type for a given entry
|
|
37
|
-
* is there when entry creation for that content type is attempted.
|
|
38
|
-
*
|
|
39
|
-
* Allows only content model or only content pushing.
|
|
40
|
-
*
|
|
41
|
-
* Options:
|
|
42
|
-
* - sourceData: see DEFAULT_CONTENT_STRUCTURE
|
|
43
|
-
* - destinationData: see DEFAULT_CONTENT_STRUCTURE
|
|
44
|
-
* - client: preconfigured management API client
|
|
45
|
-
* - spaceId: ID of space content is being copied to
|
|
46
|
-
* - contentModelOnly: synchronizes only content types and locales
|
|
47
|
-
* - skipLocales: skips locales when synchronizing the content model
|
|
48
|
-
* - skipContentModel: synchronizes only entries and assets
|
|
49
|
-
* - skipContentPublishing: create content but don't publish it
|
|
50
|
-
* - uploadAssets: upload exported files instead of pointing to an existing URL
|
|
51
|
-
* - assetsDirectory: path to exported asset files to be uploaded instead of pointing to an existing URL
|
|
52
|
-
*/
|
|
53
|
-
|
|
54
|
-
function pushToSpace({
|
|
55
|
-
sourceData,
|
|
56
|
-
destinationData = {},
|
|
57
|
-
client,
|
|
58
|
-
spaceId,
|
|
59
|
-
environmentId,
|
|
60
|
-
contentModelOnly,
|
|
61
|
-
skipContentModel,
|
|
62
|
-
skipLocales,
|
|
63
|
-
skipContentPublishing,
|
|
64
|
-
timeout,
|
|
65
|
-
retryLimit,
|
|
66
|
-
listrOptions,
|
|
67
|
-
uploadAssets,
|
|
68
|
-
assetsDirectory,
|
|
69
|
-
requestQueue
|
|
70
|
-
}) {
|
|
71
|
-
sourceData = _objectSpread(_objectSpread({}, DEFAULT_CONTENT_STRUCTURE), sourceData);
|
|
72
|
-
destinationData = _objectSpread(_objectSpread({}, DEFAULT_CONTENT_STRUCTURE), destinationData);
|
|
73
|
-
listrOptions = listrOptions || {
|
|
74
|
-
renderer: _listrVerboseRenderer.default
|
|
75
|
-
};
|
|
76
|
-
const destinationDataById = {};
|
|
77
|
-
for (const [entityType, entities] of Object.entries(destinationData)) {
|
|
78
|
-
const entitiesById = new Map();
|
|
79
|
-
for (const entity of entities) {
|
|
80
|
-
entitiesById.set(entity.sys.id, entity);
|
|
81
|
-
}
|
|
82
|
-
destinationDataById[entityType] = entitiesById;
|
|
83
|
-
}
|
|
84
|
-
return new _listr.default([{
|
|
85
|
-
title: 'Connecting to space',
|
|
86
|
-
task: (0, _listr2.wrapTask)(async (ctx, task) => {
|
|
87
|
-
const space = await client.getSpace(spaceId);
|
|
88
|
-
const environment = await space.getEnvironment(environmentId);
|
|
89
|
-
ctx.space = space;
|
|
90
|
-
ctx.environment = environment;
|
|
91
|
-
})
|
|
92
|
-
}, {
|
|
93
|
-
title: 'Importing Locales',
|
|
94
|
-
task: (0, _listr2.wrapTask)(async (ctx, task) => {
|
|
95
|
-
const locales = await creation.createLocales({
|
|
96
|
-
context: {
|
|
97
|
-
target: ctx.environment,
|
|
98
|
-
type: 'Locale'
|
|
99
|
-
},
|
|
100
|
-
entities: sourceData.locales,
|
|
101
|
-
destinationEntitiesById: destinationDataById.locales,
|
|
102
|
-
requestQueue
|
|
103
|
-
});
|
|
104
|
-
ctx.data.locales = locales;
|
|
105
|
-
}),
|
|
106
|
-
skip: () => skipContentModel || skipLocales
|
|
107
|
-
}, {
|
|
108
|
-
title: 'Importing Content Types',
|
|
109
|
-
task: (0, _listr2.wrapTask)(async (ctx, task) => {
|
|
110
|
-
const contentTypes = await creation.createEntities({
|
|
111
|
-
context: {
|
|
112
|
-
target: ctx.environment,
|
|
113
|
-
type: 'ContentType'
|
|
114
|
-
},
|
|
115
|
-
entities: sourceData.contentTypes,
|
|
116
|
-
destinationEntitiesById: destinationDataById.contentTypes,
|
|
117
|
-
requestQueue
|
|
118
|
-
});
|
|
119
|
-
ctx.data.contentTypes = contentTypes;
|
|
120
|
-
}),
|
|
121
|
-
skip: () => skipContentModel
|
|
122
|
-
}, {
|
|
123
|
-
title: 'Publishing Content Types',
|
|
124
|
-
task: (0, _listr2.wrapTask)(async (ctx, task) => {
|
|
125
|
-
const publishedContentTypes = await publishEntities({
|
|
126
|
-
entities: ctx.data.contentTypes,
|
|
127
|
-
sourceEntities: sourceData.contentTypes,
|
|
128
|
-
requestQueue
|
|
129
|
-
});
|
|
130
|
-
ctx.data.contentTypes = publishedContentTypes;
|
|
131
|
-
}),
|
|
132
|
-
skip: ctx => skipContentModel
|
|
133
|
-
}, {
|
|
134
|
-
title: 'Importing Tags',
|
|
135
|
-
task: (0, _listr2.wrapTask)(async (ctx, task) => {
|
|
136
|
-
const tags = await creation.createEntities({
|
|
137
|
-
context: {
|
|
138
|
-
target: ctx.environment,
|
|
139
|
-
type: 'Tag'
|
|
140
|
-
},
|
|
141
|
-
entities: sourceData.tags,
|
|
142
|
-
destinationEntitiesById: destinationDataById.tags,
|
|
143
|
-
requestQueue
|
|
144
|
-
});
|
|
145
|
-
ctx.data.tags = tags;
|
|
146
|
-
}),
|
|
147
|
-
// we remove `tags` from destination data if an error was thrown trying to access them
|
|
148
|
-
// this means the user doesn't have access to this feature, skip importing tags
|
|
149
|
-
skip: () => !destinationDataById.tags
|
|
150
|
-
}, {
|
|
151
|
-
title: 'Importing Editor Interfaces',
|
|
152
|
-
task: (0, _listr2.wrapTask)(async (ctx, task) => {
|
|
153
|
-
const allEditorInterfacesBeingFetched = ctx.data.contentTypes.map(async contentType => {
|
|
154
|
-
const editorInterface = sourceData.editorInterfaces.find(editorInterface => {
|
|
155
|
-
return editorInterface.sys.contentType.sys.id === contentType.sys.id;
|
|
156
|
-
});
|
|
157
|
-
if (!editorInterface) {
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
try {
|
|
161
|
-
const ctEditorInterface = await requestQueue.add(() => ctx.environment.getEditorInterfaceForContentType(contentType.sys.id));
|
|
162
|
-
_logging.logEmitter.emit('info', `Fetched editor interface for ${contentType.name}`);
|
|
163
|
-
ctEditorInterface.controls = editorInterface.controls;
|
|
164
|
-
ctEditorInterface.groupControls = editorInterface.groupControls;
|
|
165
|
-
ctEditorInterface.editorLayout = editorInterface.editorLayout;
|
|
166
|
-
const updatedEditorInterface = await requestQueue.add(() => ctEditorInterface.update());
|
|
167
|
-
return updatedEditorInterface;
|
|
168
|
-
} catch (err) {
|
|
169
|
-
err.entity = editorInterface;
|
|
170
|
-
throw err;
|
|
171
|
-
}
|
|
172
|
-
});
|
|
173
|
-
const allEditorInterfaces = await Promise.all(allEditorInterfacesBeingFetched);
|
|
174
|
-
const editorInterfaces = allEditorInterfaces.filter(editorInterface => editorInterface);
|
|
175
|
-
ctx.data.editorInterfaces = editorInterfaces;
|
|
176
|
-
}),
|
|
177
|
-
skip: ctx => skipContentModel || ctx.data.contentTypes.length === 0
|
|
178
|
-
}, {
|
|
179
|
-
title: 'Uploading Assets',
|
|
180
|
-
task: (0, _listr2.wrapTask)(async (ctx, task) => {
|
|
181
|
-
const allPendingUploads = [];
|
|
182
|
-
for (const asset of sourceData.assets) {
|
|
183
|
-
for (const file of Object.values(asset.transformed.fields.file)) {
|
|
184
|
-
allPendingUploads.push(requestQueue.add(async () => {
|
|
185
|
-
try {
|
|
186
|
-
_logging.logEmitter.emit('info', `Uploading Asset file ${file.upload}`);
|
|
187
|
-
const assetStream = await assets.getAssetStreamForURL(file.upload, assetsDirectory);
|
|
188
|
-
const upload = await ctx.environment.createUpload({
|
|
189
|
-
fileName: asset.transformed.sys.id,
|
|
190
|
-
file: assetStream
|
|
191
|
-
});
|
|
192
|
-
delete file.upload;
|
|
193
|
-
file.uploadFrom = {
|
|
194
|
-
sys: {
|
|
195
|
-
type: 'Link',
|
|
196
|
-
linkType: 'Upload',
|
|
197
|
-
id: upload.sys.id
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
return upload;
|
|
201
|
-
} catch (err) {
|
|
202
|
-
_logging.logEmitter.emit('error', err);
|
|
203
|
-
}
|
|
204
|
-
}));
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// We call the pending uploads for the side effects
|
|
209
|
-
// so we can just await all pending ones that are queued
|
|
210
|
-
const uploads = await Promise.all(allPendingUploads);
|
|
211
|
-
ctx.data.uploadedAssetFiles = uploads;
|
|
212
|
-
}),
|
|
213
|
-
skip: ctx => !uploadAssets || !sourceData.assets.length
|
|
214
|
-
}, {
|
|
215
|
-
title: 'Importing Assets',
|
|
216
|
-
task: (0, _listr2.wrapTask)(async (ctx, task) => {
|
|
217
|
-
const assetsToProcess = await creation.createEntities({
|
|
218
|
-
context: {
|
|
219
|
-
target: ctx.environment,
|
|
220
|
-
type: 'Asset'
|
|
221
|
-
},
|
|
222
|
-
entities: sourceData.assets,
|
|
223
|
-
destinationEntitiesById: destinationDataById.assets,
|
|
224
|
-
requestQueue
|
|
225
|
-
});
|
|
226
|
-
const processedAssets = await assets.processAssets({
|
|
227
|
-
assets: assetsToProcess,
|
|
228
|
-
timeout,
|
|
229
|
-
retryLimit,
|
|
230
|
-
requestQueue
|
|
231
|
-
});
|
|
232
|
-
ctx.data.assets = processedAssets;
|
|
233
|
-
}),
|
|
234
|
-
skip: ctx => contentModelOnly
|
|
235
|
-
}, {
|
|
236
|
-
title: 'Publishing Assets',
|
|
237
|
-
task: (0, _listr2.wrapTask)(async (ctx, task) => {
|
|
238
|
-
const publishedAssets = await publishEntities({
|
|
239
|
-
entities: ctx.data.assets,
|
|
240
|
-
sourceEntities: sourceData.assets,
|
|
241
|
-
requestQueue
|
|
242
|
-
});
|
|
243
|
-
ctx.data.publishedAssets = publishedAssets;
|
|
244
|
-
}),
|
|
245
|
-
skip: ctx => contentModelOnly || skipContentPublishing
|
|
246
|
-
}, {
|
|
247
|
-
title: 'Archiving Assets',
|
|
248
|
-
task: (0, _listr2.wrapTask)(async (ctx, task) => {
|
|
249
|
-
const archivedAssets = await archiveEntities({
|
|
250
|
-
entities: ctx.data.assets,
|
|
251
|
-
sourceEntities: sourceData.assets,
|
|
252
|
-
requestQueue
|
|
253
|
-
});
|
|
254
|
-
ctx.data.archivedAssets = archivedAssets;
|
|
255
|
-
}),
|
|
256
|
-
skip: ctx => contentModelOnly || skipContentPublishing
|
|
257
|
-
}, {
|
|
258
|
-
title: 'Importing Content Entries',
|
|
259
|
-
task: (0, _listr2.wrapTask)(async (ctx, task) => {
|
|
260
|
-
const entries = await creation.createEntries({
|
|
261
|
-
context: {
|
|
262
|
-
target: ctx.environment,
|
|
263
|
-
skipContentModel
|
|
264
|
-
},
|
|
265
|
-
entities: sourceData.entries,
|
|
266
|
-
destinationEntitiesById: destinationDataById.entries,
|
|
267
|
-
requestQueue
|
|
268
|
-
});
|
|
269
|
-
ctx.data.entries = entries;
|
|
270
|
-
}),
|
|
271
|
-
skip: ctx => contentModelOnly
|
|
272
|
-
}, {
|
|
273
|
-
title: 'Publishing Content Entries',
|
|
274
|
-
task: (0, _listr2.wrapTask)(async (ctx, task) => {
|
|
275
|
-
const publishedEntries = await publishEntities({
|
|
276
|
-
entities: ctx.data.entries,
|
|
277
|
-
sourceEntities: sourceData.entries,
|
|
278
|
-
requestQueue
|
|
279
|
-
});
|
|
280
|
-
ctx.data.publishedEntries = publishedEntries;
|
|
281
|
-
}),
|
|
282
|
-
skip: ctx => contentModelOnly || skipContentPublishing
|
|
283
|
-
}, {
|
|
284
|
-
title: 'Archiving Entries',
|
|
285
|
-
task: (0, _listr2.wrapTask)(async (ctx, task) => {
|
|
286
|
-
const archivedEntries = await archiveEntities({
|
|
287
|
-
entities: ctx.data.entries,
|
|
288
|
-
sourceEntities: sourceData.entries,
|
|
289
|
-
requestQueue
|
|
290
|
-
});
|
|
291
|
-
ctx.data.archivedEntries = archivedEntries;
|
|
292
|
-
}),
|
|
293
|
-
skip: ctx => contentModelOnly || skipContentPublishing
|
|
294
|
-
}, {
|
|
295
|
-
title: 'Creating Web Hooks',
|
|
296
|
-
task: (0, _listr2.wrapTask)(async (ctx, task) => {
|
|
297
|
-
const webhooks = await creation.createEntities({
|
|
298
|
-
context: {
|
|
299
|
-
target: ctx.space,
|
|
300
|
-
type: 'Webhook'
|
|
301
|
-
},
|
|
302
|
-
entities: sourceData.webhooks,
|
|
303
|
-
destinationEntitiesById: destinationDataById.webhooks,
|
|
304
|
-
requestQueue
|
|
305
|
-
});
|
|
306
|
-
ctx.data.webhooks = webhooks;
|
|
307
|
-
}),
|
|
308
|
-
skip: ctx => contentModelOnly || environmentId !== 'master' && 'Webhooks can only be imported in master environment'
|
|
309
|
-
}], listrOptions);
|
|
310
|
-
}
|
|
311
|
-
function archiveEntities({
|
|
312
|
-
entities,
|
|
313
|
-
sourceEntities,
|
|
314
|
-
requestQueue
|
|
315
|
-
}) {
|
|
316
|
-
const entityIdsToArchive = sourceEntities.filter(({
|
|
317
|
-
original
|
|
318
|
-
}) => original.sys.archivedVersion).map(({
|
|
319
|
-
original
|
|
320
|
-
}) => original.sys.id);
|
|
321
|
-
const entitiesToArchive = entities.filter(entity => entityIdsToArchive.indexOf(entity.sys.id) !== -1);
|
|
322
|
-
return publishing.archiveEntities({
|
|
323
|
-
entities: entitiesToArchive,
|
|
324
|
-
requestQueue
|
|
325
|
-
});
|
|
326
|
-
}
|
|
327
|
-
function publishEntities({
|
|
328
|
-
entities,
|
|
329
|
-
sourceEntities,
|
|
330
|
-
requestQueue
|
|
331
|
-
}) {
|
|
332
|
-
// Find all entities in source content which are published
|
|
333
|
-
const entityIdsToPublish = sourceEntities.filter(({
|
|
334
|
-
original
|
|
335
|
-
}) => original.sys.publishedVersion).map(({
|
|
336
|
-
original
|
|
337
|
-
}) => original.sys.id);
|
|
338
|
-
|
|
339
|
-
// Filter imported entities and publish only these who got published in the source
|
|
340
|
-
const entitiesToPublish = entities.filter(entity => entityIdsToPublish.indexOf(entity.sys.id) !== -1);
|
|
341
|
-
return publishing.publishEntities({
|
|
342
|
-
entities: entitiesToPublish,
|
|
343
|
-
requestQueue
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
module.exports = exports.default;
|