@jungvonmatt/contentful-migrations 6.2.6 → 7.0.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 +22 -11
- package/cli.js +314 -171
- package/index.d.ts +9 -9
- package/lib/backend.js +146 -102
- package/lib/content.js +5 -5
- package/lib/contentful.js +90 -43
- package/lib/diff.js +46 -32
- package/lib/helpers/locale.d.ts +3 -3
- package/lib/helpers/validation.d.ts +94 -15
- package/lib/helpers/validation.js +4 -4
- package/lib/migration.js +64 -51
- package/package.json +54 -117
- package/lib/helpers/validation.test.js +0 -381
- package/lib/helpers/validation.utils.test.js +0 -45
package/index.d.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import type Migration from
|
|
2
|
-
import type { MigrationContext, MigrationFunction } from
|
|
3
|
-
import type { LocaleHelpers } from
|
|
4
|
-
import type { ValidationHelpers } from
|
|
1
|
+
import type Migration from 'contentful-migration';
|
|
2
|
+
import type { MigrationContext, MigrationFunction } from 'contentful-migration';
|
|
3
|
+
import type { LocaleHelpers } from './lib/helpers/locale';
|
|
4
|
+
import type { ValidationHelpers } from './lib/helpers/validation';
|
|
5
5
|
|
|
6
6
|
export interface MigrationHelpers {
|
|
7
|
-
locale: LocaleHelpers
|
|
8
|
-
validation: ValidationHelpers
|
|
7
|
+
locale: LocaleHelpers;
|
|
8
|
+
validation: ValidationHelpers;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export type EnhancedMigrationFunction = (
|
|
12
12
|
migration: Migration,
|
|
13
13
|
context?: MigrationContext,
|
|
14
|
-
helpers?: MigrationHelpers
|
|
14
|
+
helpers?: MigrationHelpers,
|
|
15
15
|
) => void;
|
|
16
16
|
|
|
17
17
|
export function withHelpers(cb: EnhancedMigrationFunction): MigrationFunction;
|
|
18
|
-
export { getLocaleHelpers } from
|
|
19
|
-
export { getValidationHelpers } from
|
|
18
|
+
export { getLocaleHelpers } from './lib/helpers/locale';
|
|
19
|
+
export { getValidationHelpers } from './lib/helpers/validation';
|
package/lib/backend.js
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
const path = require(
|
|
2
|
-
const fs = require(
|
|
3
|
-
const pc = require(
|
|
4
|
-
const cliProgress = require(
|
|
5
|
-
const {
|
|
6
|
-
const {
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const fs = require("fs/promises");
|
|
3
|
+
const pc = require("picocolors");
|
|
4
|
+
const cliProgress = require("cli-progress");
|
|
5
|
+
const { glob } = require("tinyglobby");
|
|
6
|
+
const {
|
|
7
|
+
getEnvironment,
|
|
8
|
+
getDefaultLocale,
|
|
9
|
+
getMigrationItems,
|
|
10
|
+
} = require("./contentful");
|
|
11
|
+
const {
|
|
12
|
+
STORAGE_TAG,
|
|
13
|
+
STORAGE_CONTENT,
|
|
14
|
+
STATE_SUCCESS,
|
|
15
|
+
STATE_FAILURE,
|
|
16
|
+
} = require("./config");
|
|
7
17
|
|
|
8
18
|
/**
|
|
9
19
|
* Create contentful-migrations content-type
|
|
@@ -15,79 +25,90 @@ const initializeContentModel = async (config) => {
|
|
|
15
25
|
const environmentId = client.sys.id;
|
|
16
26
|
const { items: contentTypes } = await client.getContentTypes();
|
|
17
27
|
|
|
18
|
-
const exists = (contentTypes || []).some(
|
|
28
|
+
const exists = (contentTypes || []).some(
|
|
29
|
+
(contentType) => contentType.sys.id === migrationContentTypeId,
|
|
30
|
+
);
|
|
19
31
|
|
|
20
32
|
if (!exists) {
|
|
21
33
|
console.log(
|
|
22
|
-
`\nCreating content-type: ${pc.green(migrationContentTypeId)} in environment ${pc.green(environmentId)}
|
|
34
|
+
`\nCreating content-type: ${pc.green(migrationContentTypeId)} in environment ${pc.green(environmentId)}`,
|
|
35
|
+
);
|
|
36
|
+
const contentType = await client.createContentTypeWithId(
|
|
37
|
+
migrationContentTypeId,
|
|
38
|
+
{
|
|
39
|
+
name: "Migrations",
|
|
40
|
+
description: "Internal data model holding references to all migrations",
|
|
41
|
+
displayField: "name",
|
|
42
|
+
fields: [
|
|
43
|
+
{
|
|
44
|
+
id: "version",
|
|
45
|
+
name: "Version",
|
|
46
|
+
type: "Symbol",
|
|
47
|
+
localized: false,
|
|
48
|
+
required: true,
|
|
49
|
+
validations: [],
|
|
50
|
+
disabled: false,
|
|
51
|
+
omitted: false,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "name",
|
|
55
|
+
name: "Name",
|
|
56
|
+
type: "Symbol",
|
|
57
|
+
localized: false,
|
|
58
|
+
required: false,
|
|
59
|
+
validations: [],
|
|
60
|
+
disabled: false,
|
|
61
|
+
omitted: false,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: "state",
|
|
65
|
+
name: "State",
|
|
66
|
+
type: "Symbol",
|
|
67
|
+
localized: false,
|
|
68
|
+
required: false,
|
|
69
|
+
validations: [
|
|
70
|
+
{
|
|
71
|
+
in: [STATE_SUCCESS, STATE_FAILURE],
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
disabled: false,
|
|
75
|
+
omitted: false,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: "message",
|
|
79
|
+
name: "Message",
|
|
80
|
+
type: "Text",
|
|
81
|
+
localized: false,
|
|
82
|
+
required: false,
|
|
83
|
+
validations: [],
|
|
84
|
+
disabled: false,
|
|
85
|
+
omitted: false,
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
},
|
|
23
89
|
);
|
|
24
|
-
const contentType = await client.createContentTypeWithId(migrationContentTypeId, {
|
|
25
|
-
name: 'Migrations',
|
|
26
|
-
description: 'Internal data model holding references to all migrations',
|
|
27
|
-
displayField: 'name',
|
|
28
|
-
fields: [
|
|
29
|
-
{
|
|
30
|
-
id: 'version',
|
|
31
|
-
name: 'Version',
|
|
32
|
-
type: 'Symbol',
|
|
33
|
-
localized: false,
|
|
34
|
-
required: true,
|
|
35
|
-
validations: [],
|
|
36
|
-
disabled: false,
|
|
37
|
-
omitted: false,
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
id: 'name',
|
|
41
|
-
name: 'Name',
|
|
42
|
-
type: 'Symbol',
|
|
43
|
-
localized: false,
|
|
44
|
-
required: false,
|
|
45
|
-
validations: [],
|
|
46
|
-
disabled: false,
|
|
47
|
-
omitted: false,
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
id: 'state',
|
|
51
|
-
name: 'State',
|
|
52
|
-
type: 'Symbol',
|
|
53
|
-
localized: false,
|
|
54
|
-
required: false,
|
|
55
|
-
validations: [
|
|
56
|
-
{
|
|
57
|
-
in: [STATE_SUCCESS, STATE_FAILURE],
|
|
58
|
-
},
|
|
59
|
-
],
|
|
60
|
-
disabled: false,
|
|
61
|
-
omitted: false,
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
id: 'message',
|
|
65
|
-
name: 'Message',
|
|
66
|
-
type: 'Text',
|
|
67
|
-
localized: false,
|
|
68
|
-
required: false,
|
|
69
|
-
validations: [],
|
|
70
|
-
disabled: false,
|
|
71
|
-
omitted: false,
|
|
72
|
-
},
|
|
73
|
-
],
|
|
74
|
-
});
|
|
75
90
|
await contentType.publish();
|
|
76
91
|
|
|
77
|
-
const editorInterface = await client.getEditorInterfaceForContentType(
|
|
92
|
+
const editorInterface = await client.getEditorInterfaceForContentType(
|
|
93
|
+
migrationContentTypeId,
|
|
94
|
+
);
|
|
78
95
|
if (editorInterface) {
|
|
79
|
-
const messageIndex = editorInterface.controls.findIndex(
|
|
96
|
+
const messageIndex = editorInterface.controls.findIndex(
|
|
97
|
+
(value) => value.fieldId === "message",
|
|
98
|
+
);
|
|
80
99
|
editorInterface.controls[messageIndex] = {
|
|
81
100
|
...editorInterface.controls[messageIndex],
|
|
82
|
-
widgetNamespace:
|
|
83
|
-
widgetId:
|
|
101
|
+
widgetNamespace: "builtin",
|
|
102
|
+
widgetId: "multipleLine",
|
|
84
103
|
};
|
|
85
104
|
|
|
86
|
-
const stateIndex = editorInterface.controls.findIndex(
|
|
105
|
+
const stateIndex = editorInterface.controls.findIndex(
|
|
106
|
+
(value) => value.fieldId === "state",
|
|
107
|
+
);
|
|
87
108
|
editorInterface.controls[stateIndex] = {
|
|
88
109
|
...editorInterface.controls[stateIndex],
|
|
89
|
-
widgetNamespace:
|
|
90
|
-
widgetId:
|
|
110
|
+
widgetNamespace: "builtin",
|
|
111
|
+
widgetId: "radio",
|
|
91
112
|
};
|
|
92
113
|
|
|
93
114
|
await editorInterface.update();
|
|
@@ -116,26 +137,30 @@ const addMigrationEntry = async (data, config) => {
|
|
|
116
137
|
} catch {}
|
|
117
138
|
|
|
118
139
|
if (!entry) {
|
|
119
|
-
entry = await client.createEntryWithId(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
140
|
+
entry = await client.createEntryWithId(
|
|
141
|
+
migrationContentTypeId,
|
|
142
|
+
`${version}`,
|
|
143
|
+
{
|
|
144
|
+
fields: {
|
|
145
|
+
version: {
|
|
146
|
+
[defaultLocale]: `${version}`,
|
|
147
|
+
},
|
|
148
|
+
name: {
|
|
149
|
+
[defaultLocale]: name,
|
|
150
|
+
},
|
|
151
|
+
state: {
|
|
152
|
+
[defaultLocale]: state,
|
|
153
|
+
},
|
|
154
|
+
message: {
|
|
155
|
+
[defaultLocale]: message || "",
|
|
156
|
+
},
|
|
132
157
|
},
|
|
133
158
|
},
|
|
134
|
-
|
|
159
|
+
);
|
|
135
160
|
} else {
|
|
136
161
|
entry.fields.name = { [defaultLocale]: name };
|
|
137
162
|
entry.fields.state = { [defaultLocale]: state };
|
|
138
|
-
entry.fields.message = { [defaultLocale]: message ||
|
|
163
|
+
entry.fields.message = { [defaultLocale]: message || "" };
|
|
139
164
|
}
|
|
140
165
|
|
|
141
166
|
try {
|
|
@@ -200,8 +225,9 @@ const migrateToContentStorage = async (config) => {
|
|
|
200
225
|
const client = await getEnvironment(config);
|
|
201
226
|
const version = await getMigrationVersionFromTag(config);
|
|
202
227
|
|
|
203
|
-
const
|
|
204
|
-
|
|
228
|
+
const migrations = await glob([`${directory}/*.js`, `${directory}/*.cjs`], {
|
|
229
|
+
absolute: true,
|
|
230
|
+
});
|
|
205
231
|
const environmentId = client.sys.id;
|
|
206
232
|
const filtered = migrations.filter((file) => {
|
|
207
233
|
const name = path.basename(file);
|
|
@@ -210,11 +236,13 @@ const migrateToContentStorage = async (config) => {
|
|
|
210
236
|
return version && parseInt(version, 10) >= parseInt(num, 10);
|
|
211
237
|
});
|
|
212
238
|
|
|
213
|
-
console.log(
|
|
239
|
+
console.log(
|
|
240
|
+
`\nFound ${pc.green(filtered.length)} executed migrations in environment ${pc.green(environmentId)}`,
|
|
241
|
+
);
|
|
214
242
|
|
|
215
243
|
const bar = new cliProgress.SingleBar(
|
|
216
|
-
{ format:
|
|
217
|
-
cliProgress.Presets.legacy
|
|
244
|
+
{ format: "Adding content-entries: {value}/{total} | ETA: {eta}s" },
|
|
245
|
+
cliProgress.Presets.legacy,
|
|
218
246
|
);
|
|
219
247
|
let progress = 0;
|
|
220
248
|
|
|
@@ -223,7 +251,10 @@ const migrateToContentStorage = async (config) => {
|
|
|
223
251
|
const name = path.basename(file);
|
|
224
252
|
const [, num] = /^(\d+)-/.exec(name);
|
|
225
253
|
|
|
226
|
-
await addMigrationEntry(
|
|
254
|
+
await addMigrationEntry(
|
|
255
|
+
{ version: num, name, state: STATE_SUCCESS },
|
|
256
|
+
config,
|
|
257
|
+
);
|
|
227
258
|
progress++;
|
|
228
259
|
bar.update(progress);
|
|
229
260
|
}
|
|
@@ -235,7 +266,7 @@ const migrateToContentStorage = async (config) => {
|
|
|
235
266
|
await migrationTag.delete();
|
|
236
267
|
} catch {}
|
|
237
268
|
}
|
|
238
|
-
console.log(
|
|
269
|
+
console.log("All done 👍🏼");
|
|
239
270
|
};
|
|
240
271
|
|
|
241
272
|
/**
|
|
@@ -248,24 +279,30 @@ const migrateToTagStorage = async (config) => {
|
|
|
248
279
|
const oldVersion = await getMigrationVersionFromTag(config);
|
|
249
280
|
if (migrationContentTypeId) {
|
|
250
281
|
const client = await getEnvironment(config);
|
|
251
|
-
const { items } = await client.getEntries({
|
|
282
|
+
const { items } = await client.getEntries({
|
|
283
|
+
content_type: migrationContentTypeId,
|
|
284
|
+
});
|
|
252
285
|
|
|
253
286
|
const version =
|
|
254
287
|
items.length &&
|
|
255
288
|
Math.max(
|
|
256
289
|
...items
|
|
257
|
-
.filter(
|
|
258
|
-
|
|
290
|
+
.filter(
|
|
291
|
+
(item) => item?.fields?.state?.[defaultLocale] === STATE_SUCCESS,
|
|
292
|
+
)
|
|
293
|
+
.map((item) => parseInt(item.sys.id, 10)),
|
|
259
294
|
);
|
|
260
295
|
|
|
261
296
|
if (version && (oldVersion || 0) < version) {
|
|
262
|
-
console.log(
|
|
297
|
+
console.log(
|
|
298
|
+
`\nAdding ${pc.green(fieldId)} tag with version ${pc.green(version)}`,
|
|
299
|
+
);
|
|
263
300
|
await setMigrationTag(version, config);
|
|
264
301
|
}
|
|
265
302
|
|
|
266
303
|
const bar = new cliProgress.SingleBar(
|
|
267
|
-
{ format:
|
|
268
|
-
cliProgress.Presets.legacy
|
|
304
|
+
{ format: "Removing content-entries: {value}/{total} | ETA: {eta}s" },
|
|
305
|
+
cliProgress.Presets.legacy,
|
|
269
306
|
);
|
|
270
307
|
let progress = 0;
|
|
271
308
|
|
|
@@ -288,7 +325,7 @@ const migrateToTagStorage = async (config) => {
|
|
|
288
325
|
}
|
|
289
326
|
}
|
|
290
327
|
|
|
291
|
-
console.log(
|
|
328
|
+
console.log("All done 👍🏼");
|
|
292
329
|
};
|
|
293
330
|
|
|
294
331
|
/**
|
|
@@ -371,8 +408,9 @@ const getVersionFromFile = (file) => {
|
|
|
371
408
|
*/
|
|
372
409
|
const getNewMigrations = async (config) => {
|
|
373
410
|
const { directory, storage, migrationContentTypeId } = config || {};
|
|
374
|
-
const
|
|
375
|
-
|
|
411
|
+
const migrations = (
|
|
412
|
+
await glob([`${directory}/*.js`, `${directory}/*.cjs`], { absolute: true })
|
|
413
|
+
).sort((a, b) => {
|
|
376
414
|
const numA = getVersionFromFile(a);
|
|
377
415
|
const numB = getVersionFromFile(b);
|
|
378
416
|
return (numA || 0) - (numB || 0);
|
|
@@ -387,21 +425,27 @@ const getNewMigrations = async (config) => {
|
|
|
387
425
|
});
|
|
388
426
|
|
|
389
427
|
return result;
|
|
390
|
-
} catch
|
|
428
|
+
} catch {
|
|
391
429
|
// check if we have a migration scheduled which adds the initial content-type
|
|
392
|
-
const regexp = new RegExp(
|
|
430
|
+
const regexp = new RegExp(
|
|
431
|
+
`createContentType\\(['"]${migrationContentTypeId}['"]\\)`,
|
|
432
|
+
"mg",
|
|
433
|
+
);
|
|
393
434
|
const initial = (
|
|
394
435
|
await Promise.all(
|
|
395
436
|
migrations.map(async (file) => {
|
|
396
|
-
return fs.readFile(file,
|
|
397
|
-
})
|
|
437
|
+
return fs.readFile(file, "utf8");
|
|
438
|
+
}),
|
|
398
439
|
)
|
|
399
440
|
).some((content) => regexp.test(content));
|
|
400
441
|
|
|
401
442
|
if (initial) {
|
|
402
443
|
return migrations;
|
|
403
444
|
}
|
|
404
|
-
console.error(
|
|
445
|
+
console.error(
|
|
446
|
+
pc.red("\nError:"),
|
|
447
|
+
`Missing migration content type. Run ${pc.cyan("npx migrations init")}`,
|
|
448
|
+
);
|
|
405
449
|
process.exit(1);
|
|
406
450
|
}
|
|
407
451
|
}
|
package/lib/content.js
CHANGED
|
@@ -61,8 +61,8 @@ const transferContent = async (config) => {
|
|
|
61
61
|
if (sourceVersion !== destVersion) {
|
|
62
62
|
throw new Error(
|
|
63
63
|
`Different migration states detected. ${pc.bold(sourceEnvironmentId)} (${sourceVersion}) !== ${pc.bold(
|
|
64
|
-
destEnvironmentId
|
|
65
|
-
)} (${destVersion})
|
|
64
|
+
destEnvironmentId,
|
|
65
|
+
)} (${destVersion})`,
|
|
66
66
|
);
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -72,7 +72,7 @@ const transferContent = async (config) => {
|
|
|
72
72
|
entries: sourceEntries,
|
|
73
73
|
assets: sourceAssetsBase,
|
|
74
74
|
filteredEntries,
|
|
75
|
-
contentTypes:
|
|
75
|
+
contentTypes: _sourceContentTypes,
|
|
76
76
|
} = await getContent({
|
|
77
77
|
...config,
|
|
78
78
|
environmentId: sourceEnvironmentId,
|
|
@@ -147,8 +147,8 @@ const transferContent = async (config) => {
|
|
|
147
147
|
|
|
148
148
|
console.log(
|
|
149
149
|
`${br}Transfering ${pc.cyan(`${entries.length} Entries`)} and ${pc.cyan(`${assets.length} Assets`)} from ${pc.cyan(
|
|
150
|
-
sourceEnvironmentId
|
|
151
|
-
)} to ${pc.cyan(destEnvironmentId)}
|
|
150
|
+
sourceEnvironmentId,
|
|
151
|
+
)} to ${pc.cyan(destEnvironmentId)}`,
|
|
152
152
|
);
|
|
153
153
|
|
|
154
154
|
proceed = await confirm(config);
|
package/lib/contentful.js
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
const contentful = require(
|
|
2
|
-
const
|
|
3
|
-
const hasher = require('node-object-hash');
|
|
1
|
+
const contentful = require("contentful-management");
|
|
2
|
+
const { hasher } = require("node-object-hash");
|
|
4
3
|
const objectHash = hasher();
|
|
5
4
|
|
|
6
5
|
let client;
|
|
7
6
|
let environmentCache = new Map();
|
|
8
7
|
let spaceCache = new Map();
|
|
9
8
|
|
|
10
|
-
const TYPE_SYMBOL =
|
|
11
|
-
const TYPE_TEXT =
|
|
12
|
-
const TYPE_RICHTEXT =
|
|
13
|
-
const TYPE_NUMBER =
|
|
14
|
-
const TYPE_DATE =
|
|
15
|
-
const TYPE_LOCATION =
|
|
16
|
-
const TYPE_ARRAY =
|
|
17
|
-
const TYPE_BOOLEAN =
|
|
18
|
-
const TYPE_LINK =
|
|
19
|
-
const LINK_TYPE_ASSET =
|
|
20
|
-
const LINK_TYPE_ENTRY =
|
|
9
|
+
const TYPE_SYMBOL = "Symbol";
|
|
10
|
+
const TYPE_TEXT = "Text";
|
|
11
|
+
const TYPE_RICHTEXT = "RichText";
|
|
12
|
+
const TYPE_NUMBER = "Integer";
|
|
13
|
+
const TYPE_DATE = "Date";
|
|
14
|
+
const TYPE_LOCATION = "Location";
|
|
15
|
+
const TYPE_ARRAY = "Array";
|
|
16
|
+
const TYPE_BOOLEAN = "Boolean";
|
|
17
|
+
const TYPE_LINK = "Link";
|
|
18
|
+
const LINK_TYPE_ASSET = "Asset";
|
|
19
|
+
const LINK_TYPE_ENTRY = "Entry";
|
|
21
20
|
|
|
22
21
|
const MAX_ALLOWED_LIMIT = 1000;
|
|
23
22
|
|
|
@@ -47,13 +46,13 @@ const getContentId = (node) => {
|
|
|
47
46
|
|
|
48
47
|
const getContentName = (node, displayField) => {
|
|
49
48
|
const { fields, sys } = node;
|
|
50
|
-
const { id: fallback =
|
|
49
|
+
const { id: fallback = "unknown" } = sys || {};
|
|
51
50
|
const { [displayField]: field, name, title, id } = fields || {};
|
|
52
51
|
|
|
53
52
|
for (const tmp of [field, name, title, id].filter((v) => v)) {
|
|
54
53
|
const [result] = Object.values(tmp);
|
|
55
54
|
|
|
56
|
-
if (result && typeof result ===
|
|
55
|
+
if (result && typeof result === "string") {
|
|
57
56
|
return result;
|
|
58
57
|
}
|
|
59
58
|
}
|
|
@@ -81,10 +80,13 @@ const getClient = async (options) => {
|
|
|
81
80
|
return client;
|
|
82
81
|
}
|
|
83
82
|
|
|
84
|
-
throw new Error(
|
|
83
|
+
throw new Error("You need to login first. Run npx contentful login");
|
|
85
84
|
};
|
|
86
85
|
|
|
87
|
-
const getSpaces = async (
|
|
86
|
+
const getSpaces = async (
|
|
87
|
+
options,
|
|
88
|
+
{ skip = 0, aggregatedResponse = null } = {},
|
|
89
|
+
) => {
|
|
88
90
|
const client = await getClient(options);
|
|
89
91
|
const query = {
|
|
90
92
|
skip: skip,
|
|
@@ -132,7 +134,10 @@ const getEnvironments = async (options) => {
|
|
|
132
134
|
return environments;
|
|
133
135
|
};
|
|
134
136
|
|
|
135
|
-
const getApiKeys = async (
|
|
137
|
+
const getApiKeys = async (
|
|
138
|
+
options,
|
|
139
|
+
{ skip = 0, aggregatedResponse = null } = {},
|
|
140
|
+
) => {
|
|
136
141
|
const space = await getSpace(options);
|
|
137
142
|
const query = {
|
|
138
143
|
skip: skip,
|
|
@@ -177,10 +182,12 @@ const getEnvironment = async (options) => {
|
|
|
177
182
|
if (targetEnvironmentId && environmentIds.includes(targetEnvironmentId)) {
|
|
178
183
|
environmentCache.set(cacheKey, space.getEnvironment(targetEnvironmentId));
|
|
179
184
|
} else if (targetEnvironmentId) {
|
|
180
|
-
throw new Error(
|
|
185
|
+
throw new Error(
|
|
186
|
+
`Environment "${targetEnvironmentId}" is not available in space "${spaceId}"`,
|
|
187
|
+
);
|
|
181
188
|
} else {
|
|
182
189
|
throw new Error(
|
|
183
|
-
|
|
190
|
+
"Missing environment id. Use -e <environment-id> or set environment variable CONTENTFUL_ENVIRONMENT_ID",
|
|
184
191
|
);
|
|
185
192
|
}
|
|
186
193
|
|
|
@@ -198,7 +205,7 @@ const getDefaultLocale = async (config) => {
|
|
|
198
205
|
|
|
199
206
|
const defaultLocale = locales.find((locale) => locale.default);
|
|
200
207
|
const { code } = defaultLocale || {};
|
|
201
|
-
return code ||
|
|
208
|
+
return code || "de";
|
|
202
209
|
};
|
|
203
210
|
|
|
204
211
|
/**
|
|
@@ -210,12 +217,15 @@ const getDefaultLocale = async (config) => {
|
|
|
210
217
|
* - getEntries
|
|
211
218
|
* - getAssets
|
|
212
219
|
*/
|
|
213
|
-
const pagedGet = async (
|
|
220
|
+
const pagedGet = async (
|
|
221
|
+
environment,
|
|
222
|
+
{ method, skip = 0, aggregatedResponse = null, query = null },
|
|
223
|
+
) => {
|
|
214
224
|
const fullQuery = {
|
|
215
225
|
skip: skip,
|
|
216
226
|
limit: MAX_ALLOWED_LIMIT,
|
|
217
|
-
order:
|
|
218
|
-
...
|
|
227
|
+
order: "sys.createdAt,sys.id",
|
|
228
|
+
...query,
|
|
219
229
|
};
|
|
220
230
|
|
|
221
231
|
const response = await environment[method](fullQuery);
|
|
@@ -227,17 +237,28 @@ const pagedGet = async (environment, { method, skip = 0, aggregatedResponse = nu
|
|
|
227
237
|
}
|
|
228
238
|
|
|
229
239
|
if (skip + fullQuery.limit <= response.total) {
|
|
230
|
-
return pagedGet(environment, {
|
|
240
|
+
return pagedGet(environment, {
|
|
241
|
+
method,
|
|
242
|
+
skip: skip + fullQuery.limit,
|
|
243
|
+
aggregatedResponse,
|
|
244
|
+
query,
|
|
245
|
+
});
|
|
231
246
|
}
|
|
232
247
|
return aggregatedResponse;
|
|
233
248
|
};
|
|
234
249
|
|
|
235
|
-
const
|
|
236
|
-
return includeDrafts
|
|
250
|
+
const _filterDrafts = (items, includeDrafts) => {
|
|
251
|
+
return includeDrafts
|
|
252
|
+
? items
|
|
253
|
+
: items.filter(
|
|
254
|
+
(item) => !!item.sys.publishedVersion || !!item.sys.archivedVersion,
|
|
255
|
+
);
|
|
237
256
|
};
|
|
238
257
|
|
|
239
|
-
const
|
|
240
|
-
return includeArchived
|
|
258
|
+
const _filterArchived = (items, includeArchived) => {
|
|
259
|
+
return includeArchived
|
|
260
|
+
? items
|
|
261
|
+
: items.filter((item) => !item.sys.archivedVersion);
|
|
241
262
|
};
|
|
242
263
|
|
|
243
264
|
const getLinkedId = (node, destType) => {
|
|
@@ -251,7 +272,7 @@ const getLinkedId = (node, destType) => {
|
|
|
251
272
|
const getLinkedIds = (entry, destType) => {
|
|
252
273
|
const { fields } = entry || {};
|
|
253
274
|
const ids = Object.values(fields).reduce((result, locales) => {
|
|
254
|
-
const ids =
|
|
275
|
+
const ids = Object.values(locales).flatMap((value) => {
|
|
255
276
|
if (Array.isArray(value)) {
|
|
256
277
|
return value.map((node) => getLinkedId(node, destType));
|
|
257
278
|
}
|
|
@@ -271,15 +292,26 @@ const getLinkedEntries = (entries, allEntries, options) => {
|
|
|
271
292
|
return [];
|
|
272
293
|
}
|
|
273
294
|
const entryIds = (entries || []).map((entry) => getContentId(entry));
|
|
274
|
-
const linkedIds = (entries || []).reduce(
|
|
295
|
+
const linkedIds = (entries || []).reduce(
|
|
296
|
+
(result, entry) => [...result, ...getLinkedIds(entry, LINK_TYPE_ENTRY)],
|
|
297
|
+
[],
|
|
298
|
+
);
|
|
275
299
|
const newIds = linkedIds.filter(
|
|
276
|
-
(id) =>
|
|
300
|
+
(id) =>
|
|
301
|
+
!collectedIds.includes(id) &&
|
|
302
|
+
!entryIds.includes(id) &&
|
|
303
|
+
includeIds.includes(id),
|
|
304
|
+
);
|
|
305
|
+
const newEntries = allEntries.filter((entry) =>
|
|
306
|
+
newIds.includes(getContentId(entry)),
|
|
277
307
|
);
|
|
278
|
-
const newEntries = allEntries.filter((entry) => newIds.includes(getContentId(entry)));
|
|
279
308
|
|
|
280
309
|
return [
|
|
281
310
|
...newEntries,
|
|
282
|
-
...getLinkedEntries(newEntries, allEntries, {
|
|
311
|
+
...getLinkedEntries(newEntries, allEntries, {
|
|
312
|
+
...options,
|
|
313
|
+
collectedIds: [...collectedIds, ...entryIds],
|
|
314
|
+
}),
|
|
283
315
|
];
|
|
284
316
|
};
|
|
285
317
|
|
|
@@ -287,7 +319,10 @@ const getLinkedAssets = (entries, assets) => {
|
|
|
287
319
|
if ((entries || []).length === 0) {
|
|
288
320
|
return [];
|
|
289
321
|
}
|
|
290
|
-
const linkedIds = (entries || []).reduce(
|
|
322
|
+
const linkedIds = (entries || []).reduce(
|
|
323
|
+
(result, entry) => [...result, ...getLinkedIds(entry, LINK_TYPE_ASSET)],
|
|
324
|
+
[],
|
|
325
|
+
);
|
|
291
326
|
|
|
292
327
|
return assets.filter((asset) => linkedIds.includes(getContentId(asset)));
|
|
293
328
|
};
|
|
@@ -305,12 +340,20 @@ const getContent = async (options) => {
|
|
|
305
340
|
const { contentType } = options;
|
|
306
341
|
const environment = await getEnvironment(options);
|
|
307
342
|
|
|
308
|
-
const { items: contentTypes } = await pagedGet(environment, {
|
|
309
|
-
|
|
310
|
-
|
|
343
|
+
const { items: contentTypes } = await pagedGet(environment, {
|
|
344
|
+
method: "getContentTypes",
|
|
345
|
+
});
|
|
346
|
+
const { items: entries } = await pagedGet(environment, {
|
|
347
|
+
method: "getEntries",
|
|
348
|
+
});
|
|
349
|
+
const { items: assets } = await pagedGet(environment, {
|
|
350
|
+
method: "getAssets",
|
|
351
|
+
});
|
|
311
352
|
|
|
312
353
|
if (contentType) {
|
|
313
|
-
const baseEntries = entries.filter(
|
|
354
|
+
const baseEntries = entries.filter(
|
|
355
|
+
(entry) => getContentTypeId(entry) === contentType,
|
|
356
|
+
);
|
|
314
357
|
|
|
315
358
|
return {
|
|
316
359
|
entries,
|
|
@@ -328,7 +371,7 @@ const getMigrationItems = async (options) => {
|
|
|
328
371
|
const { migrationContentTypeId } = options;
|
|
329
372
|
const environment = await getEnvironment(options);
|
|
330
373
|
const { items } = await pagedGet(environment, {
|
|
331
|
-
method:
|
|
374
|
+
method: "getEntries",
|
|
332
375
|
query: { content_type: migrationContentTypeId },
|
|
333
376
|
});
|
|
334
377
|
|
|
@@ -339,7 +382,9 @@ const getContentTypes = async (options) => {
|
|
|
339
382
|
const { contentType } = options;
|
|
340
383
|
const environment = await getEnvironment(options);
|
|
341
384
|
|
|
342
|
-
const { items: contentTypes } = await pagedGet(environment, {
|
|
385
|
+
const { items: contentTypes } = await pagedGet(environment, {
|
|
386
|
+
method: "getContentTypes",
|
|
387
|
+
});
|
|
343
388
|
|
|
344
389
|
if (contentType) {
|
|
345
390
|
return contentTypes.filter((entry) => getContentId(entry) === contentType);
|
|
@@ -351,7 +396,9 @@ const getContentTypes = async (options) => {
|
|
|
351
396
|
const getEditorInterfaces = async (options) => {
|
|
352
397
|
const environment = await getEnvironment(options);
|
|
353
398
|
|
|
354
|
-
const { items: editorInterfaces } = await pagedGet(environment, {
|
|
399
|
+
const { items: editorInterfaces } = await pagedGet(environment, {
|
|
400
|
+
method: "getEditorInterfaces",
|
|
401
|
+
});
|
|
355
402
|
|
|
356
403
|
return editorInterfaces;
|
|
357
404
|
};
|