contensis-cli 1.0.12-beta.2 → 1.0.12-beta.20

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.
Files changed (71) hide show
  1. package/README.md +9 -9
  2. package/dist/commands/get.js +13 -1
  3. package/dist/commands/get.js.map +2 -2
  4. package/dist/commands/globalOptions.js +9 -10
  5. package/dist/commands/globalOptions.js.map +2 -2
  6. package/dist/commands/import.js +22 -12
  7. package/dist/commands/import.js.map +2 -2
  8. package/dist/commands/index.js +2 -2
  9. package/dist/commands/index.js.map +2 -2
  10. package/dist/commands/list.js +9 -0
  11. package/dist/commands/list.js.map +2 -2
  12. package/dist/commands/remove.js +13 -0
  13. package/dist/commands/remove.js.map +2 -2
  14. package/dist/localisation/en-GB.js +12 -4
  15. package/dist/localisation/en-GB.js.map +2 -2
  16. package/dist/mappers/DevInit-to-CIWorkflow.js +6 -8
  17. package/dist/mappers/DevInit-to-CIWorkflow.js.map +2 -2
  18. package/dist/mappers/DevInit-to-RolePermissions.js +4 -4
  19. package/dist/mappers/DevInit-to-RolePermissions.js.map +2 -2
  20. package/dist/providers/file-provider.js +5 -1
  21. package/dist/providers/file-provider.js.map +2 -2
  22. package/dist/services/ContensisAuthService.js.map +2 -2
  23. package/dist/services/ContensisCliService.js +158 -40
  24. package/dist/services/ContensisCliService.js.map +2 -2
  25. package/dist/services/ContensisDevService.js +51 -56
  26. package/dist/services/ContensisDevService.js.map +3 -3
  27. package/dist/shell.js +6 -0
  28. package/dist/shell.js.map +2 -2
  29. package/dist/util/console.printer.js +61 -52
  30. package/dist/util/console.printer.js.map +3 -3
  31. package/dist/util/csv.formatter.js +3 -11
  32. package/dist/util/csv.formatter.js.map +3 -3
  33. package/dist/util/diff.js +1 -1
  34. package/dist/util/diff.js.map +2 -2
  35. package/dist/util/error.js +36 -0
  36. package/dist/util/error.js.map +7 -0
  37. package/dist/util/find.js +10 -2
  38. package/dist/util/find.js.map +2 -2
  39. package/dist/util/git.js +1 -0
  40. package/dist/util/git.js.map +2 -2
  41. package/dist/util/json.formatter.js +35 -3
  42. package/dist/util/json.formatter.js.map +3 -3
  43. package/dist/util/logger.js +52 -9
  44. package/dist/util/logger.js.map +3 -3
  45. package/dist/version.js +1 -1
  46. package/dist/version.js.map +1 -1
  47. package/package.json +4 -4
  48. package/src/commands/get.ts +19 -1
  49. package/src/commands/globalOptions.ts +9 -7
  50. package/src/commands/import.ts +35 -15
  51. package/src/commands/index.ts +2 -3
  52. package/src/commands/list.ts +15 -0
  53. package/src/commands/remove.ts +20 -0
  54. package/src/localisation/en-GB.ts +15 -5
  55. package/src/mappers/DevInit-to-CIWorkflow.ts +8 -8
  56. package/src/mappers/DevInit-to-RolePermissions.ts +5 -2
  57. package/src/models/Cache.d.ts +2 -1
  58. package/src/providers/file-provider.ts +5 -1
  59. package/src/services/ContensisAuthService.ts +1 -1
  60. package/src/services/ContensisCliService.ts +195 -55
  61. package/src/services/ContensisDevService.ts +76 -70
  62. package/src/shell.ts +8 -0
  63. package/src/util/console.printer.ts +151 -72
  64. package/src/util/csv.formatter.ts +1 -4
  65. package/src/util/diff.ts +1 -1
  66. package/src/util/error.ts +7 -0
  67. package/src/util/find.ts +13 -2
  68. package/src/util/git.ts +2 -1
  69. package/src/util/json.formatter.ts +32 -1
  70. package/src/util/logger.ts +90 -15
  71. package/src/version.ts +1 -1
@@ -1,6 +1,8 @@
1
+ import ansiEscapes from 'ansi-escapes';
1
2
  import to from 'await-to-js';
2
3
  import { spawn } from 'child_process';
3
4
  import inquirer from 'inquirer';
5
+ import { createSpinner } from 'nanospinner';
4
6
  import path from 'path';
5
7
 
6
8
  import { Role } from 'contensis-management-api/lib/models';
@@ -20,15 +22,17 @@ import { GitHelper } from '~/util/git';
20
22
  import { jsonFormatter } from '~/util/json.formatter';
21
23
  import { winSlash } from '~/util/os';
22
24
  import { stringifyYaml } from '~/util/yaml';
23
- import { createSpinner } from 'nanospinner';
24
25
  import { mergeContentsToAddWithGitignore } from '~/util/gitignore';
25
- import ContensisAuthService from './ContensisAuthService';
26
- import ansiEscapes from 'ansi-escapes';
27
26
 
28
27
  class ContensisDev extends ContensisRole {
29
28
  git!: GitHelper;
30
29
  blockId!: string;
31
30
 
31
+ deployCredentials = {
32
+ clientId: '',
33
+ clientSecret: '',
34
+ };
35
+
32
36
  constructor(
33
37
  args: string[],
34
38
  outputOpts?: OutputOptionsConstructorArg,
@@ -49,8 +53,6 @@ class ContensisDev extends ContensisRole {
49
53
  const contensis = await this.ConnectContensis();
50
54
 
51
55
  if (contensis) {
52
- this.devinit = { ...this.devinit, invokedBy: this.invokedBy };
53
-
54
56
  // First we need to get the block id from the user
55
57
  const validateBlockId = (blockId: string) => {
56
58
  const pattern = /^[0-9a-z](-?[0-9a-z])*$/;
@@ -64,6 +66,7 @@ class ContensisDev extends ContensisRole {
64
66
  prefix: '🧱',
65
67
  message: messages.devinit.blockIdQuestion,
66
68
  validate: validateBlockId,
69
+ default: git.name,
67
70
  });
68
71
  // make sure block id is lowercase
69
72
  this.blockId = blockId.toLowerCase();
@@ -93,65 +96,17 @@ class ContensisDev extends ContensisRole {
93
96
  const devKeyDescription = `Created by Contensis to allow API access from the running block`;
94
97
  let existingDevKey = apiKeyExists(devKeyName);
95
98
 
96
- // if dev api key doesn't exisit go and create it (we need this for local development, we will store these details in the .env file).
97
- if (!existingDevKey) {
98
- existingDevKey = await this.CreateOrUpdateApiKey(
99
- existingDevKey,
100
- devKeyName,
101
- devKeyDescription
102
- );
103
- log.success('Successfully created development key');
104
- }
105
-
106
99
  const deployKeyName = `${apiKeyName}-ci`;
107
100
  const deployKeyDescription = `Created by the Contensis CLI for use in continuous integration`;
108
101
 
109
102
  let existingDeployKey = apiKeyExists(deployKeyName);
110
103
 
111
- // if deploy api key doesn't exisit go and create it (we need this for yml file).
112
- if (!existingDeployKey) {
113
- existingDeployKey = await this.CreateOrUpdateApiKey(
114
- existingDeployKey,
115
- deployKeyName,
116
- deployKeyDescription
117
- );
118
- log.success('Successfully created deploy key');
119
- }
120
-
121
- // check we have the deply key so we can assign them to this values
122
- if (existingDeployKey) {
123
- // Add client id and secret to global 'this'
124
- this.devinit = {
125
- ...this.devinit,
126
- credentials: {
127
- clientId: existingDeployKey?.id,
128
- clientSecret: existingDeployKey?.sharedSecret,
129
- },
130
- };
131
- }
132
-
133
- // we need to credentials of the user so that we can create a auth service
134
- const credentials = await this.GetCredentials(this.devinit.invokedBy);
135
-
136
- // create new auth service using creds
137
- let classicToken: string | undefined | null;
138
- const auth = new ContensisAuthService({
139
- username: credentials?.current?.account,
140
- password: credentials?.current?.password,
141
- projectId: currentProject,
142
- rootUrl: `https://cms-${currentEnv}.cloud.contensis.com`,
143
- });
144
-
145
- // once we have auth service, we can go and fetch out classic token
146
- classicToken = await auth.ClassicToken();
147
-
148
104
  // const blockId = git.name;
149
105
  const errors = [] as AppError[];
150
106
 
151
107
  // Start render console output
152
108
  log.raw('');
153
109
  log.success(messages.devinit.intro());
154
- log.raw('');
155
110
  log.raw(
156
111
  log.infoText(
157
112
  messages.devinit.projectDetails(
@@ -193,7 +148,6 @@ class ContensisDev extends ContensisRole {
193
148
 
194
149
  log.raw(log.infoText(messages.devinit.ciDetails(ciFileName)));
195
150
 
196
- let mappedWorkflow;
197
151
  // Location for Client ID / Secret.
198
152
  const { loc } = await inquirer.prompt({
199
153
  name: 'loc',
@@ -213,9 +167,8 @@ class ContensisDev extends ContensisRole {
213
167
  ],
214
168
  });
215
169
 
170
+ log.raw('');
216
171
  log.help(messages.devinit.ciIntro(git, loc));
217
- // Update CI Workflow
218
- mappedWorkflow = await mapCIWorkflowContent(this, loc);
219
172
 
220
173
  if (!dryRun) {
221
174
  // Confirm prompt
@@ -233,7 +186,6 @@ class ContensisDev extends ContensisRole {
233
186
 
234
187
  // Fetching access token
235
188
  let accessToken: string | undefined = undefined;
236
- log.raw('');
237
189
 
238
190
  const spinner = createSpinner(messages.devinit.accessTokenFetch());
239
191
  spinner.start();
@@ -241,9 +193,9 @@ class ContensisDev extends ContensisRole {
241
193
  const token = await this.GetDeliveryApiKey();
242
194
 
243
195
  if (token) {
244
- spinner.success();
245
- this.log.success(messages.devinit.accessTokenSuccess(token));
246
196
  accessToken = token;
197
+ spinner.success({ text: messages.devinit.accessTokenSuccess(token) });
198
+ log.raw('');
247
199
  } else {
248
200
  spinner.error();
249
201
  this.log.error(messages.devinit.accessTokenFailed());
@@ -261,9 +213,48 @@ class ContensisDev extends ContensisRole {
261
213
  const [getRolesErr, roles] = await to(contensis.roles.GetRoles());
262
214
  if (!roles && getRolesErr) errors.push(getRolesErr);
263
215
  checkpoint(`fetched ${roles?.length} roles`);
216
+
264
217
  if (dryRun) {
265
218
  checkpoint(`skip api key creation (dry-run)`);
266
219
  } else {
220
+ // if dev api key doesn't exist go and create it (we need this for local development, we will store these details in the .env file).
221
+ const devKeyExisted = !!existingDevKey;
222
+ if (!existingDevKey) {
223
+ existingDevKey = await this.CreateOrUpdateApiKey(
224
+ existingDevKey,
225
+ devKeyName,
226
+ devKeyDescription
227
+ );
228
+ log.success(messages.devinit.createDevKey(devKeyName, devKeyExisted));
229
+ }
230
+ // NF 24/11/23 Added this commented code back in as we are not assigning the dev key to any role here
231
+ // // Ensure dev API key is assigned to a role
232
+ // let existingDevRole = findByIdOrName(roles || [], devKeyName, true) as
233
+ // | Role
234
+ // | undefined;
235
+ // existingDevRole = await this.CreateOrUpdateRole(
236
+ // existingDevRole,
237
+ // devKeyRole(devKeyName, devKeyDescription)
238
+ // );
239
+ // checkpoint('dev key role assigned');
240
+
241
+ // if deploy api key doesn't exist go and create it (we need this for yml file).
242
+ const deployKeyExisted = !!existingDeployKey;
243
+ if (!existingDeployKey) {
244
+ existingDeployKey = await this.CreateOrUpdateApiKey(
245
+ existingDeployKey,
246
+ deployKeyName,
247
+ deployKeyDescription
248
+ );
249
+ }
250
+
251
+ // check we have the deploy key so we can assign them to this values
252
+ if (existingDeployKey) {
253
+ // Add client id and secret to credentials
254
+ this.deployCredentials.clientId = existingDeployKey?.id;
255
+ this.deployCredentials.clientSecret = existingDeployKey?.sharedSecret;
256
+ }
257
+
267
258
  // Ensure deploy API key is assigned to a role with the right permissions
268
259
  const deployRoleName = `Role for CI push of block '${blockId}'`;
269
260
  const deplyRoleDescription = `Created by the Contensis CLI for use in continuous integration`;
@@ -274,11 +265,13 @@ class ContensisDev extends ContensisRole {
274
265
  ) as Role | undefined;
275
266
  existingDeployRole = await this.CreateOrUpdateRole(
276
267
  existingDeployRole,
277
- deployKeyRole(deployKeyName, deplyRoleDescription)
268
+ deployKeyRole(deployKeyName, deployRoleName, deplyRoleDescription)
278
269
  );
279
270
 
280
271
  checkpoint('deploy key role assigned');
281
- log.success(messages.devinit.createDeployKey(deployRoleName, true));
272
+ log.success(
273
+ messages.devinit.createDeployKey(deployRoleName, deployKeyExisted)
274
+ );
282
275
  checkpoint('api keys done');
283
276
  }
284
277
 
@@ -297,9 +290,11 @@ class ContensisDev extends ContensisRole {
297
290
  if (accessToken) envContentsToAdd['ACCESS_TOKEN'] = accessToken;
298
291
  // add client id and secret to the env file
299
292
  if (loc === 'env') {
300
- envContentsToAdd['CONTENSIS_CLIENT_ID'] = existingDevKey?.id;
293
+ envContentsToAdd['CONTENSIS_CLIENT_ID'] =
294
+ existingDevKey?.id || messages.devinit.dryRunKeyMessage(dryRun);
301
295
  envContentsToAdd['CONTENSIS_CLIENT_SECRET'] =
302
- existingDevKey?.sharedSecret;
296
+ existingDevKey?.sharedSecret ||
297
+ messages.devinit.dryRunKeyMessage(dryRun);
303
298
  }
304
299
 
305
300
  // if we have client id / secret in our env remove it
@@ -339,7 +334,7 @@ class ContensisDev extends ContensisRole {
339
334
  }
340
335
  checkpoint('skip .env file update (dry-run)');
341
336
  } else {
342
- if (envDiff) log.info(`updating .env file ${winSlash(envFilePath)}`);
337
+ if (envDiff) log.info(`Updating .env file ${winSlash(envFilePath)}`);
343
338
  writeFile(envFilePath, envFileLines.join('\n'));
344
339
  checkpoint('.env file updated');
345
340
  log.success(messages.devinit.writeEnvFile());
@@ -347,9 +342,15 @@ class ContensisDev extends ContensisRole {
347
342
  }
348
343
 
349
344
  // Update git ignore
350
- const gitIgnorePath = `${projectHome}/.gitignore`;
351
- const gitIgnoreContentsToAdd = ['.env'];
352
- mergeContentsToAddWithGitignore(gitIgnorePath, gitIgnoreContentsToAdd);
345
+ if (dryRun) {
346
+ checkpoint('skip .gitignore file update (dry-run)');
347
+ } else {
348
+ mergeContentsToAddWithGitignore(`${projectHome}/.gitignore`, ['.env']);
349
+ log.raw('');
350
+ }
351
+
352
+ // Update CI Workflow
353
+ const mappedWorkflow = await mapCIWorkflowContent(this, loc);
353
354
 
354
355
  // Update CI file -- different for GH/GL
355
356
  if (mappedWorkflow?.diff) {
@@ -372,6 +373,7 @@ class ContensisDev extends ContensisRole {
372
373
  } else {
373
374
  log.info(messages.devinit.ciFileNoChanges(`./${ciFileName}`));
374
375
  }
376
+ log.raw('');
375
377
  checkpoint('CI file updated');
376
378
  }
377
379
  }
@@ -382,8 +384,9 @@ class ContensisDev extends ContensisRole {
382
384
  log.help(
383
385
  messages.devinit.addGitSecretsHelp(
384
386
  git,
385
- existingDeployKey?.id,
386
- existingDeployKey?.sharedSecret
387
+ existingDeployKey?.id || messages.devinit.dryRunKeyMessage(dryRun),
388
+ existingDeployKey?.sharedSecret ||
389
+ messages.devinit.dryRunKeyMessage(dryRun)
387
390
  )
388
391
  );
389
392
  }
@@ -395,10 +398,13 @@ class ContensisDev extends ContensisRole {
395
398
  log.success(messages.devinit.success());
396
399
  log.help(messages.devinit.startProjectTip());
397
400
  // open the cms link -- if no classic token just return the cms url
401
+
402
+ // go and fetch the classic token from auth service
403
+ const classicToken = await this.auth?.ClassicToken();
398
404
  log.help(
399
405
  ansiEscapes.link(
400
406
  `Open Contensis`,
401
- `https://cms-${currentEnv}.cloud.contensis.com${
407
+ `${this.urls?.cms}${
402
408
  classicToken ? `?SecurityToken=${classicToken}` : ''
403
409
  }`
404
410
  )
package/src/shell.ts CHANGED
@@ -143,6 +143,7 @@ class ContensisShell {
143
143
  'execute block action makelive',
144
144
  'execute block action rollback',
145
145
  'execute block action markasbroken',
146
+ 'get assets',
146
147
  'get block',
147
148
  'get block logs',
148
149
  'get contenttype',
@@ -151,10 +152,13 @@ class ContensisShell {
151
152
  'get nodes',
152
153
  'get model',
153
154
  'get project',
155
+ 'get proxy',
156
+ 'get renderer',
154
157
  'get role',
155
158
  'get token',
156
159
  'get version',
157
160
  'get webhook',
161
+ 'get workflow',
158
162
  'import contenttypes',
159
163
  'import components',
160
164
  'import entries',
@@ -169,11 +173,13 @@ class ContensisShell {
169
173
  'list renderers',
170
174
  'list roles',
171
175
  'list webhooks',
176
+ 'list workflows',
172
177
  'push block',
173
178
  'remove components',
174
179
  'remove contenttypes',
175
180
  'remove key',
176
181
  'remove entries',
182
+ 'remove nodes',
177
183
  'remove role',
178
184
  'set project name',
179
185
  'set project description',
@@ -299,3 +305,5 @@ process.stdin.on('data', key => {
299
305
  shell().quit();
300
306
  }
301
307
  });
308
+
309
+ // process.env.http_proxy = 'http://127.0.0.1:8888';
@@ -1,14 +1,17 @@
1
1
  import { Node } from 'contensis-delivery-api/lib/models';
2
2
  import dayjs from 'dayjs';
3
+ import { deconstructApiError } from './error';
4
+ import { Logger, addNewLines } from './logger';
3
5
  import {
4
6
  BlockVersion,
5
7
  EntriesResult,
6
8
  MigrateModelsResult,
9
+ MigrateNodesTree,
7
10
  MigrateStatus,
8
11
  NodesResult,
12
+ ProjectNodesToMigrate,
9
13
  } from 'migratortron';
10
14
  import ContensisCli from '~/services/ContensisCliService';
11
- import { Logger } from './logger';
12
15
 
13
16
  const formatDate = (date: Date | string, format = 'DD/MM/YYYY HH:mm') =>
14
17
  dayjs(date).format(format);
@@ -257,76 +260,57 @@ export const printEntriesMigrateResult = (
257
260
  ` - ${log.errorText(`errors: ${migrateResult.errors.length}`)}\n`
258
261
  );
259
262
  for (const error of migrateResult.errors)
260
- log.error(error.message || error, null, '');
263
+ log.error(error.message, null, '');
261
264
  }
262
265
  };
263
266
 
264
267
  export const printNodesMigrateResult = (
265
- { log, messages, currentProject }: ContensisCli,
268
+ { log, currentProject }: ContensisCli,
266
269
  migrateResult: NodesResult,
267
270
  {
268
271
  action = 'import',
272
+ logLimit = 50,
269
273
  showDiff = false,
270
274
  showAll = false,
271
275
  showChanged = false,
272
276
  }: {
273
277
  action?: 'import' | 'delete';
278
+ logLimit?: number;
274
279
  showDiff?: boolean;
275
280
  showAll?: boolean;
276
281
  showChanged?: boolean;
277
282
  } = {}
278
283
  ) => {
279
- console.log(``);
280
-
281
- for (const [originalId, migrateNodeId] of Object.entries(
282
- migrateResult.nodesToMigrate.nodeIds
283
- )) {
284
- if (showAll || (showChanged && migrateNodeId.status !== 'no change')) {
285
- console.log(
286
- log.infoText(
287
- `${originalId} ${`${messages.migrate.status(migrateNodeId.status)(
288
- `${migrateNodeId.status}`
289
- )}${
290
- migrateNodeId.id !== originalId ? `-> ${migrateNodeId.id}` : ''
291
- }`}`
292
- ) + ` ${log.helpText(migrateNodeId.path)} ${migrateNodeId.displayName}`
293
- );
284
+ log.raw(``);
285
+ for (const [projectId, counts] of Object.entries(migrateResult.nodes || {})) {
286
+ const importTitle =
287
+ action === 'delete'
288
+ ? `Delete from project ${log.warningText(currentProject)}`
289
+ : `Import ${
290
+ projectId && projectId !== 'null'
291
+ ? `from project ${log.highlightText(projectId)} `
292
+ : ''
293
+ }to ${log.boldText(log.warningText(currentProject))}`;
294
+ log.help(importTitle);
294
295
 
295
- if (migrateNodeId.diff && showDiff)
296
- console.log(
297
- ` ${log.highlightText(`diff:`)} ${log.infoText(
298
- highlightDiffText(migrateNodeId.diff)
299
- )}\n`
300
- );
301
- }
302
- }
303
- if (showAll || showChanged) console.log(``);
296
+ const migrateStatusAndCount = migrateResult.nodesToMigrate[
297
+ currentProject
298
+ ] as ProjectNodesToMigrate;
304
299
 
305
- for (const [projectId, counts] of Object.entries(migrateResult.nodes || {})) {
306
- log.help(
307
- `${action} from project ${
308
- action === 'delete'
309
- ? log.warningText(currentProject)
310
- : `${log.highlightText(projectId)} to ${log.boldText(
311
- log.warningText(currentProject)
312
- )}`
313
- }`
314
- );
315
- counts.totalCount;
316
- const migrateStatusAndCount = migrateResult.nodesToMigrate[currentProject];
317
300
  const existingCount =
318
301
  migrateResult.existing?.[currentProject]?.totalCount || 0;
319
- const existingPercent = ((existingCount / counts.totalCount) * 100).toFixed(
320
- 0
321
- );
322
- const noChangeOrTotalEntriesCount =
323
- typeof migrateStatusAndCount !== 'number'
324
- ? migrateStatusAndCount?.['no change'] || 0
325
- : migrateStatusAndCount;
326
- const changedPercentage = (
327
- (noChangeOrTotalEntriesCount / counts.totalCount) *
328
- 100
329
- ).toFixed(0);
302
+
303
+ const totalCount = Object.keys(migrateResult.nodesToMigrate.nodeIds).length;
304
+ const existingPercent = counts.totalCount
305
+ ? ((existingCount / totalCount) * 100).toFixed(0)
306
+ : '0';
307
+
308
+ const noChangeCount = migrateStatusAndCount?.['no change'] || 0;
309
+
310
+ const changedPercentage = counts.totalCount
311
+ ? ((noChangeCount / totalCount) * 100).toFixed(0)
312
+ : '0';
313
+
330
314
  const existingColor =
331
315
  existingPercent === '0' || action === 'delete'
332
316
  ? log.warningText
@@ -336,7 +320,9 @@ export const printNodesMigrateResult = (
336
320
  changedPercentage === '100' ? log.successText : log.warningText;
337
321
 
338
322
  console.log(
339
- ` - ${log.highlightText(`totalCount: ${counts.totalCount}`)}${
323
+ ` - ${log.highlightText(
324
+ `totalCount: ${migrateStatusAndCount.totalCount}`
325
+ )}${
340
326
  changedPercentage === '100'
341
327
  ? ''
342
328
  : existingColor(` [existing: ${`${existingPercent}%`}]`)
@@ -357,10 +343,18 @@ export const printNodesMigrateResult = (
357
343
  console.log(
358
344
  ` - ${log.errorText(`errors: ${migrateResult.errors.length}`)}\n`
359
345
  );
360
- for (const error of migrateResult.errors)
361
- log.error(error.message || error, null, '');
346
+
347
+ log.limits(
348
+ migrateResult.errors
349
+ .map(error => {
350
+ return log.errorText(deconstructApiError(error));
351
+ })
352
+ .join('\n'),
353
+ logLimit
354
+ );
362
355
  }
363
356
  };
357
+
364
358
  const highlightDiffText = (str: string) => {
365
359
  const addedRegex = new RegExp(/<<\+>>(.*?)<<\/\+>>/, 'g');
366
360
  const removedRegex = new RegExp(/<<->>(.*?)<<\/->>/, 'g');
@@ -472,41 +466,126 @@ export const printModelMigrationResult = (
472
466
  };
473
467
 
474
468
  export const printNodeTreeOutput = (
475
- { log }: ContensisCli,
476
- root: Node | undefined
469
+ { log, messages }: ContensisCli,
470
+ root: Node | MigrateNodesTree | undefined,
471
+ logDetail = 'errors',
472
+ logLimit = 1000
477
473
  ) => {
478
- log.object({ ...root, children: undefined });
479
474
  log.raw('');
475
+ const statusColour = messages.migrate.status;
476
+
477
+ if (root && 'status' in root)
478
+ log.info(
479
+ `Migrate status: ${statusColour('no change')(
480
+ 'N'
481
+ )} [no change]; ${statusColour('create')('C')} [create]; ${statusColour(
482
+ 'update'
483
+ )('U')} [update]; ${statusColour('delete')('D')} [delete]; ${statusColour(
484
+ 'error'
485
+ )('E')} [error];`
486
+ );
480
487
  log.info(
481
- `${log.highlightText('e')} = has entry; ${log.highlightText(
482
- 'c'
483
- )} = canonical; ${log.highlightText('m')} = include in menu`
488
+ `Node properties: ${log.highlightText(
489
+ 'e'
490
+ )} = has entry; ${log.highlightText('c')} = canonical; ${log.highlightText(
491
+ 'm'
492
+ )} = include in menu`
484
493
  );
494
+
485
495
  log.line();
486
496
 
487
- const outputNode = (node: Node | any, spaces: string) =>
488
- `${node.entry ? log.highlightText('e') : log.infoText('-')}${
489
- node.isCanonical ? log.highlightText('c') : log.infoText('-')
497
+ const outputNode = (
498
+ node: Node | MigrateNodesTree,
499
+ spaces: string,
500
+ isRoot = false
501
+ ) => {
502
+ const errorOutput =
503
+ 'error' in node && node.error && deconstructApiError(node.error);
504
+ const fullOutput = logDetail === 'all';
505
+ const changesOutput =
506
+ logDetail === 'changes' &&
507
+ 'status' in node &&
508
+ ['create', 'update'].includes(node.status);
509
+
510
+ const diffOutput =
511
+ (fullOutput || changesOutput || errorOutput) &&
512
+ 'diff' in node &&
513
+ node.diff?.replaceAll('\n', '');
514
+
515
+ return `${
516
+ 'status' in node
517
+ ? `${statusColour(node.status)(
518
+ node.status.substring(0, 1).toUpperCase()
519
+ )} `
520
+ : ''
521
+ }${node.entry ? log.highlightText('e') : log.infoText('-')}${
522
+ 'isCanonical' in node && node.isCanonical
523
+ ? log.highlightText('c')
524
+ : log.infoText('-')
490
525
  }${
491
526
  node.includeInMenu ? log.highlightText('m') : log.infoText('-')
492
- }${spaces}${
493
- node.isCanonical ? log.boldText(`/${node.slug}`) : `/${node.slug}`
494
- }${node.entry ? ` ${log.helpText(node.entry.sys.contentTypeId)}` : ''}${
527
+ }${spaces}${log[
528
+ 'status' in node && node.status === 'no change'
529
+ ? 'infoText'
530
+ : 'standardText'
531
+ ](
532
+ 'isCanonical' in node && node.isCanonical
533
+ ? log.boldText(fullOutput || isRoot ? node.path : `/${node.slug}`)
534
+ : fullOutput || isRoot
535
+ ? node.path
536
+ : `/${node.slug}`
537
+ )}${node.entry ? ` ${log.helpText(node.entry.sys.contentTypeId)}` : ''}${
495
538
  node.childCount ? ` +${node.childCount}` : ``
496
- } ${log.infoText(node.displayName)}`;
539
+ } ${'displayName' in node ? log.infoText(node.displayName) : ''}${
540
+ fullOutput || (changesOutput && node.id !== node.originalId)
541
+ ? `~n ${log.infoText(`id:`)} ${
542
+ node.id === node.originalId
543
+ ? node.id
544
+ : `${node.id} ${log.infoText(`<= ${node.originalId}`)}`
545
+ }`
546
+ : ''
547
+ }${
548
+ (fullOutput ||
549
+ (changesOutput && node.parentId !== node.originalParentId)) &&
550
+ node.parentId
551
+ ? `~n ${log.infoText(
552
+ `parentId: ${
553
+ node.parentId === node.originalParentId
554
+ ? node.parentId
555
+ : `${node.parentId} <= ${node.originalParentId}`
556
+ }`
557
+ )}`
558
+ : ''
559
+ }${
560
+ fullOutput && node.entry?.sys.id
561
+ ? `~n ${log.infoText(`entryId: ${node.entry.sys.id}`)}`
562
+ : ''
563
+ }${
564
+ errorOutput
565
+ ? `~n${addNewLines(` ${log.errorText(errorOutput)}`, '~n')}`
566
+ : ''
567
+ }${
568
+ diffOutput
569
+ ? `~n${addNewLines(
570
+ ` ${log.infoText(`diff: ${highlightDiffText(diffOutput)}`)}`,
571
+ '~n'
572
+ )}`
573
+ : ''
574
+ }`;
575
+ };
497
576
 
498
- const outputChildren = (root: Node | undefined, depth = 2) => {
577
+ const outputChildren = (node: Node | undefined, depth = 2) => {
499
578
  let str = '';
500
- for (const node of (root as any)?.children as Node[]) {
501
- str += `${outputNode(node, Array(depth + 1).join(' '))}\n`;
502
- if ('children' in node) str += outputChildren(node, depth + 1);
579
+ for (const child of ((node as any)?.children || []) as Node[]) {
580
+ str += `${outputNode(child, Array(depth + 1).join(' '))}\n`;
581
+ if ('children' in child) str += outputChildren(child, depth + 1);
503
582
  }
504
583
  return str;
505
584
  };
506
585
 
507
586
  const children = outputChildren(root);
508
587
  log.limits(
509
- `${outputNode(root, ' ')}${children ? `\n${children}` : ''}`,
510
- 100
588
+ `${outputNode(root || {}, ' ', true)}${children ? `\n${children}` : ''}`,
589
+ logLimit
511
590
  );
512
591
  };
@@ -1,8 +1,5 @@
1
- import { flatten } from 'flat';
2
1
  import { Parser } from 'json2csv';
3
- import cleaner from 'deep-cleaner';
4
-
5
- const flattenObject = (obj: any) => flatten(cleaner(obj, ['workflow']));
2
+ import { flattenObject } from './json.formatter';
6
3
 
7
4
  export const csvFormatter = <T>(entries: T | T[]) => {
8
5
  // Flatten the passed in object
package/src/util/diff.ts CHANGED
@@ -70,7 +70,7 @@ export const diffFileContent = (
70
70
  } else needsNewLine = true;
71
71
  }
72
72
 
73
- return output.join('');
73
+ return output.join('').replaceAll('\n\n\n', '\n\n');
74
74
  };
75
75
 
76
76
  const addDiffPositionInfo = (diff: Change[]) => {
@@ -0,0 +1,7 @@
1
+ export const deconstructApiError = (error: MappedError) => {
2
+ let inner = '';
3
+ if (error.data?.[0]) {
4
+ inner = `${error.data?.[0].Field}: ${error.data?.[0].Message}`;
5
+ }
6
+ return `${error.message} ${inner}`;
7
+ };
package/src/util/find.ts CHANGED
@@ -2,7 +2,18 @@ export const findByIdOrName = (arr: any[], idOrName: string, exact = false) =>
2
2
  arr.find(
3
3
  r =>
4
4
  r.id === idOrName ||
5
- r.name.toLowerCase() === idOrName.toLowerCase()
5
+ (typeof r.name === 'string' &&
6
+ r.name.toLowerCase() === idOrName.toLowerCase()) ||
7
+ (typeof r.name === 'object' &&
8
+ Object.values<string>(r.name || {})?.[0].toLowerCase() ===
9
+ idOrName.toLowerCase())
6
10
  ) ||
7
11
  (!exact &&
8
- arr.find(r => r.name.toLowerCase().includes(idOrName.toLowerCase())));
12
+ arr.find(
13
+ r =>
14
+ (typeof r.name === 'string' &&
15
+ r.name.toLowerCase().includes(idOrName.toLowerCase())) ||
16
+ (typeof r.name === 'object' &&
17
+ Object.values<string>(r.name || {})?.[0].toLowerCase() ===
18
+ idOrName.toLowerCase())
19
+ ));