contensis-cli 1.0.0-beta.5

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 (95) hide show
  1. package/.vscode/launch.json +15 -0
  2. package/README.md +631 -0
  3. package/cli.js +7 -0
  4. package/dist/commands/connect.js +44 -0
  5. package/dist/commands/connect.js.map +7 -0
  6. package/dist/commands/create.js +55 -0
  7. package/dist/commands/create.js.map +7 -0
  8. package/dist/commands/get.js +121 -0
  9. package/dist/commands/get.js.map +7 -0
  10. package/dist/commands/globalOptions.js +139 -0
  11. package/dist/commands/globalOptions.js.map +7 -0
  12. package/dist/commands/import.js +95 -0
  13. package/dist/commands/import.js.map +7 -0
  14. package/dist/commands/index.js +81 -0
  15. package/dist/commands/index.js.map +7 -0
  16. package/dist/commands/list.js +88 -0
  17. package/dist/commands/list.js.map +7 -0
  18. package/dist/commands/login.js +56 -0
  19. package/dist/commands/login.js.map +7 -0
  20. package/dist/commands/push.js +133 -0
  21. package/dist/commands/push.js.map +7 -0
  22. package/dist/commands/remove.js +77 -0
  23. package/dist/commands/remove.js.map +7 -0
  24. package/dist/commands/set.js +55 -0
  25. package/dist/commands/set.js.map +7 -0
  26. package/dist/index.js +32 -0
  27. package/dist/index.js.map +7 -0
  28. package/dist/localisation/en-GB.js +203 -0
  29. package/dist/localisation/en-GB.js.map +7 -0
  30. package/dist/models/AppError.d.js +2 -0
  31. package/dist/models/AppError.d.js.map +7 -0
  32. package/dist/models/Cache.d.js +2 -0
  33. package/dist/models/Cache.d.js.map +7 -0
  34. package/dist/models/JsModules.d.js +2 -0
  35. package/dist/models/JsModules.d.js.map +7 -0
  36. package/dist/providers/CredentialProvider.js +87 -0
  37. package/dist/providers/CredentialProvider.js.map +7 -0
  38. package/dist/providers/SessionCacheProvider.js +91 -0
  39. package/dist/providers/SessionCacheProvider.js.map +7 -0
  40. package/dist/providers/file-provider.js +113 -0
  41. package/dist/providers/file-provider.js.map +7 -0
  42. package/dist/services/ContensisAuthService.js +75 -0
  43. package/dist/services/ContensisAuthService.js.map +7 -0
  44. package/dist/services/ContensisCliService.js +1110 -0
  45. package/dist/services/ContensisCliService.js.map +7 -0
  46. package/dist/shell.js +261 -0
  47. package/dist/shell.js.map +7 -0
  48. package/dist/util/console.printer.js +194 -0
  49. package/dist/util/console.printer.js.map +7 -0
  50. package/dist/util/csv.formatter.js +50 -0
  51. package/dist/util/csv.formatter.js.map +7 -0
  52. package/dist/util/index.js +94 -0
  53. package/dist/util/index.js.map +7 -0
  54. package/dist/util/json.formatter.js +29 -0
  55. package/dist/util/json.formatter.js.map +7 -0
  56. package/dist/util/logger.js +184 -0
  57. package/dist/util/logger.js.map +7 -0
  58. package/dist/util/xml.formatter.js +51 -0
  59. package/dist/util/xml.formatter.js.map +7 -0
  60. package/dist/version.js +29 -0
  61. package/dist/version.js.map +7 -0
  62. package/esbuild.config.js +49 -0
  63. package/headless-setup.sh +7 -0
  64. package/package.json +59 -0
  65. package/patches/inquirer-command-prompt+0.1.0.patch +27 -0
  66. package/src/commands/connect.ts +23 -0
  67. package/src/commands/create.ts +41 -0
  68. package/src/commands/get.ts +139 -0
  69. package/src/commands/globalOptions.ts +126 -0
  70. package/src/commands/import.ts +89 -0
  71. package/src/commands/index.ts +72 -0
  72. package/src/commands/list.ts +90 -0
  73. package/src/commands/login.ts +33 -0
  74. package/src/commands/push.ts +120 -0
  75. package/src/commands/remove.ts +77 -0
  76. package/src/commands/set.ts +40 -0
  77. package/src/index.ts +19 -0
  78. package/src/localisation/en-GB.ts +211 -0
  79. package/src/models/AppError.d.ts +40 -0
  80. package/src/models/Cache.d.ts +25 -0
  81. package/src/models/JsModules.d.ts +1 -0
  82. package/src/providers/CredentialProvider.ts +88 -0
  83. package/src/providers/SessionCacheProvider.ts +74 -0
  84. package/src/providers/file-provider.ts +72 -0
  85. package/src/services/ContensisAuthService.ts +70 -0
  86. package/src/services/ContensisCliService.ts +1390 -0
  87. package/src/shell.ts +250 -0
  88. package/src/util/console.printer.ts +203 -0
  89. package/src/util/csv.formatter.ts +21 -0
  90. package/src/util/index.ts +67 -0
  91. package/src/util/json.formatter.ts +1 -0
  92. package/src/util/logger.ts +165 -0
  93. package/src/util/xml.formatter.ts +20 -0
  94. package/src/version.ts +1 -0
  95. package/tsconfig.json +22 -0
@@ -0,0 +1,1390 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import fetch from 'node-fetch';
4
+ import inquirer from 'inquirer';
5
+ import to from 'await-to-js';
6
+ import { Component, ContentType } from 'contensis-core-api';
7
+ import { isPassword, isSharedSecret, isUuid, url } from '~/util';
8
+ import SessionCacheProvider from '../providers/SessionCacheProvider';
9
+ import ContensisAuthService from './ContensisAuthService';
10
+ import CredentialProvider from '~/providers/CredentialProvider';
11
+ import { logError, Logger } from '~/util/logger';
12
+ import { LogMessages } from '~/localisation/en-GB';
13
+ import {
14
+ ContensisMigrationService,
15
+ MigrateRequest,
16
+ PushBlockParams,
17
+ SourceCms,
18
+ logEntriesTable,
19
+ } from 'migratortron';
20
+ import { Entry } from 'contensis-management-api/lib/models';
21
+
22
+ import { csvFormatter } from '~/util/csv.formatter';
23
+ import { xmlFormatter } from '~/util/xml.formatter';
24
+ import { jsonFormatter } from '~/util/json.formatter';
25
+ import { printBlockVersion, printMigrateResult } from '~/util/console.printer';
26
+ import { readJsonFile } from '~/providers/file-provider';
27
+
28
+ type OutputFormat = 'json' | 'csv' | 'xml';
29
+
30
+ type OutputOptions = {
31
+ format?: OutputFormat;
32
+ output?: string;
33
+ };
34
+
35
+ interface IConnectOptions extends IAuthOptions {
36
+ alias?: string;
37
+ projectId?: string;
38
+ }
39
+
40
+ interface IAuthOptions {
41
+ user?: string;
42
+ password?: string;
43
+ clientId?: string;
44
+ sharedSecret?: string;
45
+ }
46
+
47
+ interface IImportOptions {
48
+ sourceEnv?: string;
49
+ sourceProjectId?: string;
50
+ }
51
+
52
+ class ContensisCli {
53
+ static quit = (error?: Error) => {
54
+ process.removeAllListeners('exit');
55
+ const exitCode = error ? 1 : 0;
56
+
57
+ console.info(`\nExiting contensis-cli with exit code: ${exitCode}\n`);
58
+ process.exit(exitCode);
59
+ };
60
+
61
+ cache: SessionCache;
62
+ contensis?: ContensisMigrationService;
63
+ contensisOpts: Partial<MigrateRequest>;
64
+ contentTypes?: ContentType[];
65
+ components?: Component[];
66
+ currentEnv: string;
67
+ currentProject: string;
68
+ env: EnvironmentCache;
69
+ sourceEnv?: string;
70
+ targetEnv?: string;
71
+ urls:
72
+ | {
73
+ api: string;
74
+ cms: string;
75
+ liveWeb: string;
76
+ previewWeb: string;
77
+ iisWeb: string;
78
+ iisPreviewWeb: string;
79
+ }
80
+ | undefined;
81
+ private command: CliCommand;
82
+ private format?: OutputFormat;
83
+ private output?: string;
84
+ log = Logger;
85
+ messages = LogMessages;
86
+ private session: SessionCacheProvider;
87
+
88
+ verb: string;
89
+ noun: string;
90
+ thirdArg: string;
91
+
92
+ constructor(
93
+ args: string[],
94
+ outputOpts?: OutputOptions & IConnectOptions & IImportOptions,
95
+ contensisOpts: Partial<MigrateRequest> = {}
96
+ ) {
97
+ // console.log('args: ', JSON.stringify(args, null, 2));
98
+
99
+ const [exe, script, verb = '', noun = '', ...restArgs] = args;
100
+ this.verb = verb?.toLowerCase();
101
+ this.noun = noun?.toLowerCase();
102
+ this.thirdArg = restArgs?.[0];
103
+
104
+ const commandText = `${this.verb} ${this.noun} ${
105
+ restArgs ? restArgs.join(' ') : ''
106
+ }`.trim();
107
+
108
+ this.session = new SessionCacheProvider();
109
+ this.cache = this.session.Get();
110
+ this.contensisOpts = contensisOpts;
111
+ this.format = outputOpts?.format;
112
+ this.output =
113
+ outputOpts?.output && path.join(process.cwd(), outputOpts.output);
114
+
115
+ const currentEnvironment =
116
+ outputOpts?.alias || this.cache.currentEnvironment || '';
117
+ const environments = this.cache.environments || {};
118
+
119
+ if (!currentEnvironment) this.env = {} as EnvironmentCache;
120
+ else if (!!environments[currentEnvironment])
121
+ this.env = environments[currentEnvironment];
122
+ else {
123
+ this.env = {
124
+ history: [],
125
+ lastUserId: '',
126
+ projects: [],
127
+ versionStatus: 'latest',
128
+ };
129
+ }
130
+
131
+ const env = this.env;
132
+
133
+ if (outputOpts?.projectId) env.currentProject = outputOpts.projectId;
134
+ if (outputOpts?.user) env.lastUserId = outputOpts.user;
135
+ if (outputOpts?.password) env.passwordFallback = outputOpts.password;
136
+ if (outputOpts?.clientId) env.lastUserId = outputOpts.clientId;
137
+ if (outputOpts?.sharedSecret)
138
+ env.passwordFallback = outputOpts.sharedSecret;
139
+
140
+ this.currentEnv = currentEnvironment;
141
+ this.currentProject = env?.currentProject || 'null';
142
+ this.sourceEnv = outputOpts?.sourceEnv || currentEnvironment;
143
+
144
+ if (currentEnvironment) {
145
+ this.urls = url(currentEnvironment, env?.currentProject || 'website');
146
+ }
147
+
148
+ this.command = {
149
+ commandText,
150
+ createdDate: new Date().toISOString(),
151
+ createdUserId: env?.lastUserId,
152
+ };
153
+
154
+ if (currentEnvironment) {
155
+ env.history = [this.command];
156
+ if (commandText) {
157
+ environments[currentEnvironment] = this.env;
158
+ this.session.Update({
159
+ currentEnvironment,
160
+ environments,
161
+ history: [commandText],
162
+ });
163
+ }
164
+ }
165
+ }
166
+
167
+ PrintEnvironments = () => {
168
+ const { log, messages } = this;
169
+ const { currentEnvironment, environments = {} } = this.cache;
170
+ const envKeys = Object.keys(environments);
171
+ log.success(messages.envs.found(envKeys.length));
172
+ this.HandleFormattingAndOutput(envKeys, () => {
173
+ // print the envKeys to console
174
+ for (const env of envKeys) {
175
+ console.log(` - ${currentEnvironment === env ? '* ' : ''}${env}`);
176
+ }
177
+ });
178
+ if (envKeys.length === 0 || !currentEnvironment) {
179
+ log.help(messages.envs.tip());
180
+ }
181
+ };
182
+
183
+ Connect = async (environment: string) => {
184
+ const { cache, log, messages, session } = this;
185
+
186
+ if (environment) {
187
+ const envCache = cache.environments[environment];
188
+ if (!envCache)
189
+ cache.environments[environment] = {
190
+ versionStatus: 'published',
191
+ history: [],
192
+ lastUserId: '',
193
+ projects: [],
194
+ ...(!this.currentEnv ? this.env : {}),
195
+ };
196
+
197
+ this.env = cache.environments[environment];
198
+ this.currentEnv = environment;
199
+ this.urls = url(environment, 'website');
200
+
201
+ const [fetchErr, response] = await to(fetch(this.urls.cms));
202
+ if (response && response?.status < 400) {
203
+ log.success(messages.connect.connected(environment));
204
+
205
+ if (this.env?.lastUserId) {
206
+ await this.ConnectContensis();
207
+ await this.PrintProjects();
208
+ } else {
209
+ log.warning(messages.projects.noList());
210
+ log.help(messages.connect.tip());
211
+ // cache.environments[environment] = {
212
+ // versionStatus: 'published',
213
+ // history: [],
214
+ // lastUserId: '',
215
+ // projects: [],
216
+ // };
217
+ }
218
+
219
+ session.Update({
220
+ currentEnvironment: environment,
221
+ environments: cache.environments,
222
+ });
223
+ } else {
224
+ // Cannot reach environment - status X
225
+ log.error(
226
+ messages.connect.unreachable(this.urls.cms, response?.status || 0)
227
+ );
228
+ }
229
+ } else {
230
+ // No environment alias specified
231
+ log.error(messages.connect.noEnv());
232
+ }
233
+ };
234
+
235
+ ConnectContensis = async ({ commit = false } = {}) => {
236
+ const { contensisOpts, currentEnv, env, log, messages } = this;
237
+ const userId = env?.lastUserId;
238
+ const isGuidId = userId && isUuid(userId);
239
+
240
+ if (currentEnv && userId) {
241
+ const [credentialError, credentials] = await new CredentialProvider(
242
+ {
243
+ userId,
244
+ alias: currentEnv,
245
+ },
246
+ env.passwordFallback
247
+ ).Init();
248
+
249
+ if (credentialError && !credentials.current) {
250
+ // Log problem with Credential Provider
251
+ log.error(credentialError as any);
252
+ return;
253
+ }
254
+ const cachedPassword = credentials?.current?.password;
255
+
256
+ if (cachedPassword) {
257
+ this.contensis = new ContensisMigrationService(
258
+ {
259
+ ...contensisOpts,
260
+ source: {
261
+ url: this.urls?.cms || '',
262
+ username: !isGuidId ? userId : undefined,
263
+ password: !isGuidId ? cachedPassword : undefined,
264
+ clientId: isGuidId ? userId : undefined,
265
+ sharedSecret: isGuidId ? cachedPassword : undefined,
266
+ project: env?.currentProject || '',
267
+ assetHostname: this.urls?.previewWeb,
268
+ },
269
+ concurrency:
270
+ typeof contensisOpts.concurrency !== 'undefined'
271
+ ? contensisOpts.concurrency
272
+ : 3,
273
+ outputProgress: true,
274
+ },
275
+ !commit
276
+ );
277
+ }
278
+ } else {
279
+ if (!currentEnv) log.help(messages.connect.help());
280
+ if (!userId) log.help(messages.connect.tip());
281
+ }
282
+ };
283
+
284
+ ConnectContensisImport = async ({
285
+ commit,
286
+ source,
287
+ fileData,
288
+ fileDataType,
289
+ }: {
290
+ commit: boolean;
291
+ source: 'contensis' | 'file' | 'input';
292
+ fileData?: any[] | string;
293
+ fileDataType?: 'entries' | 'contentTypes' | 'components';
294
+ }) => {
295
+ const { contensisOpts, currentEnv, env, log, messages, sourceEnv } = this;
296
+ const environments = this.cache.environments || {};
297
+ const sourceEnvironment = environments[sourceEnv || ''] || {};
298
+ const sourceCms =
299
+ ('source' in contensisOpts && contensisOpts.source) ||
300
+ ({} as Partial<SourceCms>);
301
+ const sourceUserId =
302
+ sourceCms.clientId || sourceCms.username || sourceEnvironment.lastUserId;
303
+ const sourceProjectId =
304
+ sourceCms.project || sourceEnvironment.currentProject || 'website';
305
+ const isSourceGuidId = sourceUserId && isUuid(sourceUserId);
306
+ const sourceUrls = url(sourceEnv || '', sourceProjectId);
307
+
308
+ const sourcePassword =
309
+ sourceCms.sharedSecret ||
310
+ sourceCms.password ||
311
+ sourceEnvironment.passwordFallback;
312
+
313
+ const targetUserId = env?.lastUserId;
314
+ const isTargetGuidId = targetUserId && isUuid(targetUserId);
315
+
316
+ if (sourceUserId && currentEnv && targetUserId) {
317
+ const [sourceCredentialError, sourceCredentials] =
318
+ await new CredentialProvider(
319
+ {
320
+ userId: sourceUserId,
321
+ alias: currentEnv,
322
+ },
323
+ sourcePassword
324
+ ).Init();
325
+
326
+ if (sourceCredentialError && !sourceCredentials.current) {
327
+ // Log problem with Credential Provider
328
+ logError(sourceCredentialError);
329
+ return;
330
+ }
331
+ const cachedSourcePassword = sourceCredentials?.current?.password;
332
+
333
+ const [targetCredentialError, targetCredentials] =
334
+ await new CredentialProvider(
335
+ {
336
+ userId: targetUserId,
337
+ alias: currentEnv,
338
+ },
339
+ env.passwordFallback
340
+ ).Init();
341
+
342
+ if (targetCredentialError && !targetCredentials.current) {
343
+ // Log problem with Credential Provider
344
+ log.error(targetCredentialError as any);
345
+ return;
346
+ }
347
+ const cachedTargetPassword = targetCredentials?.current?.password;
348
+
349
+ if (cachedSourcePassword && cachedTargetPassword) {
350
+ if (source === 'file' || source === 'input') {
351
+ this.contensis = new ContensisMigrationService(
352
+ {
353
+ concurrency: 3,
354
+ outputProgress: true,
355
+ ...contensisOpts,
356
+ target: {
357
+ url: this.urls?.cms || '',
358
+ username: !isTargetGuidId ? targetUserId : undefined,
359
+ password: !isTargetGuidId ? cachedTargetPassword : undefined,
360
+ clientId: isTargetGuidId ? targetUserId : undefined,
361
+ sharedSecret: isTargetGuidId ? cachedTargetPassword : undefined,
362
+ targetProjects: [env.currentProject || ''],
363
+ assetHostname: this.urls?.previewWeb,
364
+ },
365
+ ...(fileDataType ? { [fileDataType]: fileData } : {}),
366
+ },
367
+ !commit
368
+ );
369
+ }
370
+ if (source === 'contensis') {
371
+ this.contensis = new ContensisMigrationService(
372
+ {
373
+ concurrency: 3,
374
+ outputProgress: true,
375
+ ...contensisOpts,
376
+ source: {
377
+ url: sourceUrls.cms || '',
378
+ username: !isSourceGuidId ? sourceUserId : undefined,
379
+ password: !isSourceGuidId ? cachedSourcePassword : undefined,
380
+ clientId: isSourceGuidId ? sourceUserId : undefined,
381
+ sharedSecret: isSourceGuidId ? cachedSourcePassword : undefined,
382
+ project: sourceProjectId,
383
+ assetHostname: sourceUrls.previewWeb,
384
+ },
385
+ target: {
386
+ url: this.urls?.cms || '',
387
+ username: !isTargetGuidId ? targetUserId : undefined,
388
+ password: !isTargetGuidId ? cachedTargetPassword : undefined,
389
+ clientId: isTargetGuidId ? targetUserId : undefined,
390
+ sharedSecret: isTargetGuidId ? cachedTargetPassword : undefined,
391
+ targetProjects: [env.currentProject || ''],
392
+ assetHostname: this.urls?.previewWeb,
393
+ },
394
+ },
395
+ !commit
396
+ );
397
+ }
398
+ }
399
+ } else {
400
+ if (!currentEnv) log.help(messages.connect.help());
401
+ if (!targetUserId) log.help(messages.connect.tip());
402
+ }
403
+ };
404
+
405
+ Login = async (
406
+ userId: string,
407
+ {
408
+ password = isPassword(this.env.passwordFallback),
409
+ promptPassword = true,
410
+ sharedSecret = isSharedSecret(this.env.passwordFallback),
411
+ silent = false,
412
+ }: {
413
+ password?: string;
414
+ promptPassword?: boolean;
415
+ sharedSecret?: string;
416
+ silent?: boolean;
417
+ }
418
+ ): Promise<string | undefined> => {
419
+ let inputPassword = password;
420
+ const { log, messages } = this;
421
+
422
+ if (userId) {
423
+ const { cache, currentEnv, env } = this;
424
+
425
+ if (currentEnv) {
426
+ const [credentialError, credentials] = await new CredentialProvider(
427
+ { userId, alias: currentEnv },
428
+ inputPassword || sharedSecret
429
+ ).Init();
430
+
431
+ if (credentialError && !credentials.current) {
432
+ // Log problem with Credential Provider
433
+ log.error(credentialError as any);
434
+ return;
435
+ }
436
+
437
+ if (credentials.remarks.secure !== true)
438
+ log.warning(messages.login.insecurePassword());
439
+
440
+ const cachedPassword = isPassword(credentials?.current?.password);
441
+ const cachedSecret = isSharedSecret(credentials?.current?.password);
442
+
443
+ if (
444
+ !sharedSecret &&
445
+ !inputPassword &&
446
+ !cachedPassword &&
447
+ !cachedSecret &&
448
+ promptPassword
449
+ ) {
450
+ // Password prompt
451
+ ({ inputPassword } = await inquirer.prompt([
452
+ {
453
+ type: 'password',
454
+ message: messages.login.passwordPrompt(currentEnv, userId),
455
+ name: 'inputPassword',
456
+ mask: '*',
457
+ prefix: undefined,
458
+ },
459
+ ]));
460
+ }
461
+
462
+ if (sharedSecret || cachedSecret || inputPassword || cachedPassword) {
463
+ const authService = new ContensisAuthService({
464
+ username: userId,
465
+ password: inputPassword || cachedPassword,
466
+ projectId: env?.currentProject || 'website',
467
+ rootUrl: this.urls?.cms || '',
468
+ clientId: userId,
469
+ clientSecret: sharedSecret || cachedSecret,
470
+ });
471
+
472
+ const [authError, bearerToken] = await to(authService.BearerToken());
473
+
474
+ // Login successful
475
+ if (bearerToken) {
476
+ // Set env vars
477
+ env.authToken = bearerToken;
478
+ env.lastUserId = userId;
479
+ env.passwordFallback =
480
+ credentials.remarks.secure !== true
481
+ ? credentials.current?.password
482
+ : undefined;
483
+
484
+ if (!silent) {
485
+ Logger.success(messages.login.success(currentEnv, userId));
486
+ await this.PrintProjects();
487
+ }
488
+ if (inputPassword) await credentials.Save(inputPassword);
489
+ if (sharedSecret) await credentials.Save(sharedSecret);
490
+ } else if (authError) {
491
+ Logger.error(authError.toString());
492
+ // Clear env vars
493
+ env.authToken = '';
494
+ env.lastUserId = '';
495
+ env.passwordFallback = undefined;
496
+
497
+ // If the auth error was raised using a cached password
498
+ if (
499
+ (cachedPassword || cachedSecret) &&
500
+ credentials.remarks.secure
501
+ ) {
502
+ // Remove any bad stored credential and trigger login prompt again
503
+ await credentials.Delete();
504
+ return await this.Login(userId, { password, sharedSecret });
505
+ } else {
506
+ throw new Error(messages.login.failed(currentEnv, userId));
507
+ }
508
+ }
509
+
510
+ // Persist env
511
+ this.session.Update({
512
+ environments: cache.environments,
513
+ });
514
+ return env.authToken;
515
+ } else {
516
+ Logger.error(messages.login.passwordPrompt(currentEnv, userId));
517
+ }
518
+ } else {
519
+ // No environment set, use `contensis connect {alias}` first
520
+ Logger.error(messages.login.noEnv());
521
+ }
522
+ } else {
523
+ // No user id specified
524
+ Logger.error(messages.login.noUserId());
525
+ }
526
+ };
527
+
528
+ PrintProjects = async () => {
529
+ const { cache, currentEnv, currentProject, log, messages, session } = this;
530
+ if (!this.contensis) await this.ConnectContensis();
531
+
532
+ if (this.contensis) {
533
+ // Retrieve projects list for env
534
+ const [projectsErr, projects] = await to(
535
+ this.contensis.projects.GetSourceProjects()
536
+ );
537
+
538
+ if (Array.isArray(projects)) {
539
+ // save these projects in cache
540
+ const currentVals = cache.environments[currentEnv] || {};
541
+ const nextCurrentProject =
542
+ currentProject && currentProject !== 'null'
543
+ ? currentProject
544
+ : projects.some(p => p.id === 'website')
545
+ ? 'website'
546
+ : undefined;
547
+
548
+ cache.environments[currentEnv] = {
549
+ ...currentVals,
550
+ projects: projects.map(p => p.id),
551
+ currentProject: nextCurrentProject,
552
+ };
553
+
554
+ log.success(messages.projects.list());
555
+ this.HandleFormattingAndOutput(projects, () => {
556
+ // print the projects to console
557
+ for (const project of projects) {
558
+ console.log(
559
+ ` - ${nextCurrentProject === project.id ? '* ' : ''}[${
560
+ project.primaryLanguage
561
+ }] ${project.id}`
562
+ );
563
+ }
564
+ });
565
+
566
+ session.Update({
567
+ environments: cache.environments,
568
+ });
569
+
570
+ if (nextCurrentProject) {
571
+ this.env = cache.environments[currentEnv];
572
+ this.SetProject(nextCurrentProject);
573
+ }
574
+ }
575
+
576
+ if (projectsErr) {
577
+ log.error(messages.projects.noList());
578
+ log.error(projectsErr.message);
579
+ }
580
+ // } else {
581
+ // log.warning(messages.projects.noList());
582
+ // log.help(messages.connect.tip());
583
+ }
584
+ };
585
+
586
+ SetProject = async (projectId = '') => {
587
+ const { cache, env, log, messages, session } = this;
588
+ let nextProjectId: string | undefined;
589
+ if (env?.projects.length > 0 && env?.lastUserId) {
590
+ nextProjectId = env.projects.find(
591
+ p => p.toLowerCase() === projectId.toLowerCase()
592
+ );
593
+ if (nextProjectId) {
594
+ env.currentProject = nextProjectId;
595
+ session.Update({
596
+ environments: cache.environments,
597
+ });
598
+ log.success(messages.projects.set(projectId));
599
+ } else {
600
+ log.error(messages.projects.failedSet(projectId));
601
+ }
602
+ } else {
603
+ // No projects for currentEnv, try logging in
604
+ log.warning(messages.projects.noList());
605
+ log.help(messages.connect.tip());
606
+ }
607
+ return nextProjectId;
608
+ };
609
+
610
+ SetVersion = async (versionStatus: 'latest' | 'published') => {
611
+ const { cache, env, log, messages, session } = this;
612
+ if (!['latest', 'published'].includes(versionStatus)) {
613
+ log.error(messages.version.invalid(versionStatus));
614
+ return false;
615
+ }
616
+ if (!env) {
617
+ log.help(messages.version.noEnv());
618
+ return false;
619
+ }
620
+ if (env?.projects.length > 0 && env?.lastUserId) {
621
+ env.versionStatus = versionStatus;
622
+ session.Update({
623
+ environments: cache.environments,
624
+ });
625
+ log.success(messages.version.set(this.currentEnv, versionStatus));
626
+ return true;
627
+ } else {
628
+ // No projects for currentEnv, try logging in
629
+ log.warning(messages.projects.noList());
630
+ log.help(messages.connect.tip());
631
+ return false;
632
+ }
633
+ };
634
+
635
+ HydrateContensis = async () => {
636
+ const { log } = this;
637
+ if (!this.contensis) await this.ConnectContensis();
638
+
639
+ if (this.contensis) {
640
+ // Retrieve content types list for env
641
+ const [contensisErr, models] = await to(
642
+ this.contensis.models.HydrateContensisRepositories()
643
+ );
644
+
645
+ if (contensisErr) {
646
+ log.error(contensisErr.message);
647
+ return contensisErr;
648
+ }
649
+ }
650
+ };
651
+
652
+ PrintApiKeys = async () => {
653
+ const { currentEnv, log, messages } = this;
654
+ if (!this.contensis) await this.ConnectContensis();
655
+
656
+ if (this.contensis) {
657
+ // Retrieve keys list for env
658
+ const [keysErr, apiKeys] = await this.contensis.apiKeys.GetKeys();
659
+
660
+ if (Array.isArray(apiKeys)) {
661
+ log.success(messages.keys.list(currentEnv));
662
+ this.HandleFormattingAndOutput(apiKeys, () => {
663
+ // print the keys to console
664
+ for (const {
665
+ id,
666
+ sharedSecret,
667
+ name,
668
+ description,
669
+ dateModified,
670
+ modifiedBy,
671
+ } of apiKeys) {
672
+ console.log(
673
+ ` - ${name}${
674
+ description ? ` (${description})` : ''
675
+ } [${dateModified.toString().substring(0, 10)} ${modifiedBy}]`
676
+ );
677
+ console.log(` ${id}`);
678
+ console.log(` ${sharedSecret}`);
679
+ }
680
+ });
681
+ }
682
+
683
+ if (keysErr) {
684
+ log.error(messages.keys.noList(currentEnv));
685
+ log.error(jsonFormatter(keysErr));
686
+ }
687
+ }
688
+ };
689
+
690
+ CreateApiKey = async (name: string, description?: string) => {
691
+ const { currentEnv, log, messages } = this;
692
+ if (!this.contensis) await this.ConnectContensis();
693
+
694
+ if (this.contensis) {
695
+ const [err, key] = await this.contensis.apiKeys.CreateKey(
696
+ name,
697
+ description
698
+ );
699
+
700
+ if (key) {
701
+ log.success(messages.keys.created(currentEnv, name));
702
+
703
+ // print the key details to console
704
+ console.log(
705
+ ` - ${key.name}${
706
+ key.description ? ` (${key.description})` : ''
707
+ } [${key.dateModified.toString().substring(0, 10)} ${key.modifiedBy}]`
708
+ );
709
+ console.log(` - id: ${key.id}`);
710
+ console.log(` - sharedSecret: ${key.sharedSecret}`);
711
+ }
712
+ console.log('');
713
+
714
+ if (err) {
715
+ log.error(messages.keys.failedCreate(currentEnv, name), err);
716
+ }
717
+ }
718
+ };
719
+
720
+ RemoveApiKey = async (id: string) => {
721
+ const { currentEnv, log, messages } = this;
722
+ if (!this.contensis) await this.ConnectContensis({ commit: true });
723
+
724
+ if (this.contensis) {
725
+ const [err, key] = await this.contensis.apiKeys.RemoveKey(id);
726
+
727
+ if (!err) {
728
+ log.success(messages.keys.removed(currentEnv, id));
729
+ console.log('');
730
+ } else {
731
+ log.error(messages.keys.failedRemove(currentEnv, id), err);
732
+ }
733
+ }
734
+ };
735
+
736
+ GetContentTypes = async () => {
737
+ const { currentProject, log, messages } = this;
738
+ let err;
739
+ if (!this.contensis) err = await this.HydrateContensis();
740
+
741
+ if (err) log.error(messages.contenttypes.noList(currentProject));
742
+ if (this.contensis) {
743
+ this.contentTypes = this.contensis.models.contentTypes();
744
+ this.components = this.contensis.models.components();
745
+ } else {
746
+ log.warning(messages.contenttypes.noList(currentProject));
747
+ }
748
+ };
749
+
750
+ PrintContentTypes = async () => {
751
+ const { currentProject, log, messages } = this;
752
+ await this.GetContentTypes();
753
+ if (this.contensis) {
754
+ // Retrieve content types list for env
755
+ const { contentTypes } = this;
756
+
757
+ if (Array.isArray(contentTypes)) {
758
+ log.success(messages.contenttypes.list(currentProject));
759
+ this.HandleFormattingAndOutput(contentTypes, () => {
760
+ // print the content types to console
761
+ for (const contentType of contentTypes) {
762
+ const fieldsLength = contentType.fields?.length || 0;
763
+ console.log(
764
+ ` - ${contentType.id} [${fieldsLength} field${
765
+ fieldsLength !== 1 ? 's' : ''
766
+ }]`
767
+ );
768
+ }
769
+ });
770
+ }
771
+ }
772
+ };
773
+
774
+ PrintContentType = async (contentTypeId: string) => {
775
+ const { currentProject, log, messages } = this;
776
+ await this.GetContentTypes();
777
+ if (this.contensis) {
778
+ // Retrieve content types list for env
779
+ const { contentTypes } = this;
780
+
781
+ if (Array.isArray(contentTypes)) {
782
+ const contentType = contentTypes.find(
783
+ c => c.id.toLowerCase() === contentTypeId.toLowerCase()
784
+ );
785
+ if (contentType) {
786
+ log.success(
787
+ messages.contenttypes.get(currentProject, contentType.id)
788
+ );
789
+ // print the content type to console
790
+ this.HandleFormattingAndOutput(contentType, log.object);
791
+ } else {
792
+ log.error(
793
+ messages.contenttypes.failedGet(currentProject, contentTypeId)
794
+ );
795
+ }
796
+ }
797
+ }
798
+ };
799
+
800
+ RemoveContentTypes = async (contentTypeIds: string[], commit = false) => {
801
+ const { currentProject, log, messages } = this;
802
+ if (!this.contensis)
803
+ await this.ConnectContensisImport({
804
+ source: 'input',
805
+ commit,
806
+ });
807
+ if (this.contensis) {
808
+ const [err, result] = await this.contensis.DeleteContentTypes(
809
+ contentTypeIds
810
+ );
811
+
812
+ if (err) {
813
+ log.error(
814
+ messages.contenttypes.failedRemove(
815
+ currentProject,
816
+ contentTypeIds.join('", "')
817
+ ),
818
+ err
819
+ );
820
+ } else {
821
+ log.success(
822
+ messages.contenttypes.removed(
823
+ currentProject,
824
+ contentTypeIds.join('", "'),
825
+ !this.contensis.isPreview
826
+ )
827
+ );
828
+ // print the results to console
829
+ this.HandleFormattingAndOutput(result, () =>
830
+ log.object(jsonFormatter(result))
831
+ );
832
+ }
833
+ }
834
+ };
835
+
836
+ ImportContentTypes = async (
837
+ {
838
+ commit,
839
+ fromFile,
840
+ }: {
841
+ commit: boolean;
842
+ fromFile: string;
843
+ },
844
+ contentTypeIds: string[] = []
845
+ ) => {
846
+ const { currentProject, log, messages } = this;
847
+
848
+ let fileData = fromFile ? readJsonFile<ContentType[]>(fromFile) || [] : [];
849
+ if (typeof fileData === 'string')
850
+ throw new Error(`Import file format must be of type JSON`);
851
+
852
+ if (!Array.isArray(fileData)) fileData = [fileData];
853
+
854
+ await this.ConnectContensisImport({
855
+ commit,
856
+ source: fromFile ? 'file' : 'contensis',
857
+ });
858
+
859
+ if (this.contensis) {
860
+ // Pass each content type to the target repo
861
+ for (const contentType of fileData) {
862
+ // Fix invalid data
863
+ contentType.projectId = currentProject;
864
+ delete contentType.uuid;
865
+
866
+ const [err, created, createStatus] =
867
+ await this.contensis.models.targetRepos[
868
+ currentProject
869
+ ].repo.UpsertContentType(false, contentType);
870
+
871
+ if (err) log.error(err.message, err);
872
+ if (createStatus) {
873
+ log.success(
874
+ messages.contenttypes.created(
875
+ currentProject,
876
+ contentType.id,
877
+ createStatus
878
+ )
879
+ );
880
+ // print the content type to console
881
+ this.HandleFormattingAndOutput(contentType, () => {});
882
+ }
883
+ }
884
+ }
885
+ };
886
+
887
+ PrintComponents = async () => {
888
+ const { currentProject, log, messages } = this;
889
+ await this.GetContentTypes();
890
+ if (this.contensis) {
891
+ // Retrieve components list for env
892
+ const { components } = this;
893
+
894
+ if (Array.isArray(components)) {
895
+ log.success(messages.components.list(currentProject));
896
+
897
+ this.HandleFormattingAndOutput(components, () => {
898
+ // print the components to console
899
+ for (const component of components) {
900
+ const fieldsLength = component.fields?.length || 0;
901
+ console.log(
902
+ ` - ${component.id} [${fieldsLength} field${
903
+ fieldsLength !== 1 ? 's' : ''
904
+ }]`
905
+ );
906
+ }
907
+ });
908
+ }
909
+ }
910
+ };
911
+
912
+ PrintComponent = async (componentId: string) => {
913
+ const { currentProject, log, messages } = this;
914
+ await this.GetContentTypes();
915
+ if (this.contensis) {
916
+ // Retrieve content types list for env
917
+ const { components } = this;
918
+
919
+ if (Array.isArray(components)) {
920
+ const component = components.find(
921
+ c => c.id.toLowerCase() === componentId.toLowerCase()
922
+ );
923
+ if (component) {
924
+ log.success(messages.components.get(currentProject, component.id));
925
+ // print the component to console
926
+ this.HandleFormattingAndOutput(component, log.object);
927
+ } else {
928
+ log.error(messages.components.failedGet(currentProject, componentId));
929
+ }
930
+ }
931
+ }
932
+ };
933
+
934
+ RemoveComponents = async (componentIds: string[], commit = false) => {
935
+ const { currentProject, log, messages } = this;
936
+ if (!this.contensis)
937
+ await this.ConnectContensisImport({
938
+ source: 'input',
939
+ commit,
940
+ });
941
+ if (this.contensis) {
942
+ const [err, result] = await this.contensis.DeleteContentTypes(
943
+ undefined,
944
+ componentIds
945
+ );
946
+
947
+ if (err) {
948
+ log.error(
949
+ messages.components.failedRemove(
950
+ currentProject,
951
+ componentIds.join('", "')
952
+ ),
953
+ err
954
+ );
955
+ } else {
956
+ log.success(
957
+ messages.components.removed(
958
+ currentProject,
959
+ componentIds.join('", "'),
960
+ !this.contensis.isPreview
961
+ )
962
+ );
963
+ // print the results to console
964
+ this.HandleFormattingAndOutput(result, () =>
965
+ log.info(jsonFormatter(result))
966
+ );
967
+ }
968
+ }
969
+ };
970
+
971
+ ImportComponents = async (
972
+ {
973
+ commit,
974
+ fromFile,
975
+ }: {
976
+ commit: boolean;
977
+ fromFile: string;
978
+ },
979
+ componentIds: string[] = []
980
+ ) => {
981
+ const { currentProject, log, messages } = this;
982
+
983
+ let fileData = fromFile ? readJsonFile<Component[]>(fromFile) || [] : [];
984
+ if (typeof fileData === 'string')
985
+ throw new Error(`Import file format must be of type JSON`);
986
+
987
+ if (!Array.isArray(fileData)) fileData = [fileData];
988
+
989
+ await this.ConnectContensisImport({
990
+ commit,
991
+ source: fromFile ? 'file' : 'contensis',
992
+ });
993
+
994
+ if (this.contensis) {
995
+ // Pass each component to the target repo
996
+ for (const component of fileData) {
997
+ // Fix invalid data
998
+ component.projectId = currentProject;
999
+ delete component.uuid;
1000
+
1001
+ const [err, created, createStatus] =
1002
+ await this.contensis.models.targetRepos[
1003
+ currentProject
1004
+ ].repo.UpsertComponent(false, component);
1005
+
1006
+ if (err) log.error(err.message, err);
1007
+ if (createStatus) {
1008
+ log.success(
1009
+ messages.components.created(
1010
+ currentProject,
1011
+ component.id,
1012
+ createStatus
1013
+ )
1014
+ );
1015
+ // print the component to console
1016
+ this.HandleFormattingAndOutput(component, () => {});
1017
+ }
1018
+ }
1019
+ }
1020
+ };
1021
+
1022
+ RemoveEntry = async (id: string, commit = false) => {
1023
+ const { currentEnv, log, messages } = this;
1024
+ if (!this.contensis)
1025
+ await this.ConnectContensisImport({
1026
+ source: 'input',
1027
+ commit,
1028
+ });
1029
+
1030
+ if (this.contensis) {
1031
+ if (this.contensis.isPreview) {
1032
+ console.log(log.successText(` -- PREVIEW -- `));
1033
+ } else {
1034
+ console.log(log.warningText(` *** COMMITTING DELETE *** `));
1035
+ }
1036
+ const [err, result] = await this.contensis.DeleteEntries();
1037
+ if (result)
1038
+ this.HandleFormattingAndOutput(result, () => {
1039
+ // print the migrateResult to console
1040
+ printMigrateResult(this, result, { action: 'delete' });
1041
+ });
1042
+ if (
1043
+ !err &&
1044
+ ((!commit &&
1045
+ Object.values(result.entriesToMigrate)?.[0].totalCount > 0) ||
1046
+ (commit && result.migrateResult?.deleted))
1047
+ ) {
1048
+ log.success(messages.entries.removed(currentEnv, id, commit));
1049
+ if (!commit) log.help(messages.entries.commitTip());
1050
+ } else {
1051
+ log.error(messages.entries.failedRemove(currentEnv, id), err);
1052
+ if (!Object.values(result.entriesToMigrate)?.[0].totalCount)
1053
+ log.help(messages.entries.notFound(id));
1054
+ }
1055
+ }
1056
+ };
1057
+
1058
+ GetEntries = async ({
1059
+ withDependents = false,
1060
+ }: {
1061
+ withDependents?: boolean;
1062
+ }) => {
1063
+ const { currentProject, log, messages } = this;
1064
+ await this.ConnectContensis();
1065
+
1066
+ if (this.contensis) {
1067
+ log.line();
1068
+ const entries = await this.contensis.GetEntries({ withDependents });
1069
+ this.HandleFormattingAndOutput(entries, () =>
1070
+ // print the entries to console
1071
+ logEntriesTable(
1072
+ entries,
1073
+ currentProject,
1074
+ this.contensis?.payload.query?.fields
1075
+ )
1076
+ );
1077
+ } else {
1078
+ log.warning(messages.contenttypes.noList(currentProject));
1079
+ log.help(messages.connect.tip());
1080
+ }
1081
+ };
1082
+
1083
+ ImportEntries = async ({
1084
+ commit,
1085
+ fromFile,
1086
+ }: {
1087
+ commit: boolean;
1088
+ fromFile: string;
1089
+ }) => {
1090
+ const { currentProject, log, messages } = this;
1091
+
1092
+ const fileData = fromFile ? readJsonFile<Entry[]>(fromFile) || [] : [];
1093
+ if (typeof fileData === 'string')
1094
+ throw new Error(`Import file format must be of type JSON`);
1095
+
1096
+ await this.ConnectContensisImport({
1097
+ commit,
1098
+ source: fromFile ? 'file' : 'contensis',
1099
+ fileData,
1100
+ fileDataType: 'entries',
1101
+ });
1102
+
1103
+ if (this.contensis) {
1104
+ log.line();
1105
+ if (this.contensis.isPreview) {
1106
+ console.log(log.successText(` -- IMPORT PREVIEW -- `));
1107
+ } else {
1108
+ console.log(log.warningText(` *** COMMITTING IMPORT *** `));
1109
+ }
1110
+
1111
+ const [migrateErr, migrateResult] = await this.contensis.MigrateEntries();
1112
+
1113
+ if (migrateErr) logError(migrateErr);
1114
+ else
1115
+ this.HandleFormattingAndOutput(migrateResult, () => {
1116
+ // print the migrateResult to console
1117
+ printMigrateResult(this, migrateResult);
1118
+ });
1119
+ } else {
1120
+ log.warning(messages.contenttypes.noList(currentProject));
1121
+ log.help(messages.connect.tip());
1122
+ }
1123
+ };
1124
+
1125
+ PrintWebhookSubscriptions = async (
1126
+ subscriptionIds?: string[],
1127
+ name?: string
1128
+ ) => {
1129
+ const { currentEnv, log, messages } = this;
1130
+ if (!this.contensis) await this.ConnectContensis();
1131
+ if (this.contensis) {
1132
+ // Retrieve webhooks list for env
1133
+ const [webhooksErr, webhooks] =
1134
+ await this.contensis.subscriptions.webhooks.GetSubscriptions();
1135
+
1136
+ const filteredResults =
1137
+ typeof name === 'string'
1138
+ ? webhooks.filter(w =>
1139
+ w.name?.toLowerCase().includes(name.toLowerCase())
1140
+ )
1141
+ : Array.isArray(subscriptionIds)
1142
+ ? webhooks.filter(w => subscriptionIds?.some(id => id === w.id))
1143
+ : webhooks;
1144
+
1145
+ if (Array.isArray(filteredResults)) {
1146
+ this.HandleFormattingAndOutput(filteredResults, () => {
1147
+ // print the keys to console
1148
+ log.success(messages.webhooks.list(currentEnv));
1149
+ for (const {
1150
+ id,
1151
+ description,
1152
+ method,
1153
+ name,
1154
+ version,
1155
+ url,
1156
+ } of filteredResults) {
1157
+ console.log(
1158
+ ` - ${name}${
1159
+ description ? ` (${description})` : ''
1160
+ } [${version.modified.toString().substring(0, 10)} ${
1161
+ version.modifiedBy
1162
+ }]`
1163
+ );
1164
+ console.log(` ${id}`);
1165
+ console.log(` [${method}] ${url}`);
1166
+ }
1167
+ console.log('');
1168
+ });
1169
+ }
1170
+
1171
+ if (webhooksErr) {
1172
+ log.error(messages.webhooks.noList(currentEnv));
1173
+ log.error(jsonFormatter(webhooksErr));
1174
+ }
1175
+ }
1176
+ };
1177
+
1178
+ PrintBlocks = async () => {
1179
+ const { currentEnv, log, messages } = this;
1180
+ if (!this.contensis) await this.ConnectContensis();
1181
+ if (this.contensis) {
1182
+ // Retrieve blocks list for env
1183
+ const [err, blocks] = await this.contensis.blocks.GetBlocks();
1184
+
1185
+ if (Array.isArray(blocks)) {
1186
+ this.HandleFormattingAndOutput(blocks, () => {
1187
+ // print the blocks to console
1188
+ log.success(messages.blocks.list(currentEnv));
1189
+ for (const {
1190
+ id,
1191
+ description,
1192
+ branches,
1193
+ liveVersion,
1194
+ madeLive,
1195
+ versionsSinceLive,
1196
+ } of blocks) {
1197
+ console.log(
1198
+ ` - ${id}${description ? ` (${description})` : ''}${
1199
+ madeLive
1200
+ ? ` [${madeLive.toString().substring(0, 10)} v${liveVersion}]`
1201
+ : ''
1202
+ }${
1203
+ versionsSinceLive
1204
+ ? log.warningText(` +${versionsSinceLive}`)
1205
+ : ''
1206
+ }`
1207
+ );
1208
+ for (const branch of branches)
1209
+ console.log(
1210
+ log.infoText(` [${branch.id}]: ${branch.status}`)
1211
+ );
1212
+ }
1213
+ });
1214
+ }
1215
+
1216
+ if (err) {
1217
+ log.error(messages.blocks.noList(currentEnv));
1218
+ log.error(jsonFormatter(err));
1219
+ }
1220
+ }
1221
+ };
1222
+
1223
+ PrintBlockVersions = async (
1224
+ blockId: string,
1225
+ branch: string,
1226
+ version: string
1227
+ ) => {
1228
+ const { currentEnv, env, log, messages } = this;
1229
+ if (!this.contensis) await this.ConnectContensis();
1230
+ if (this.contensis) {
1231
+ // Retrieve block version
1232
+ const [err, blocks] = await this.contensis.blocks.GetBlockVersions(
1233
+ blockId,
1234
+ branch,
1235
+ version
1236
+ );
1237
+
1238
+ if (blocks) {
1239
+ this.HandleFormattingAndOutput(blocks, () => {
1240
+ // print the version detail to console
1241
+ log.success(
1242
+ messages.blocks.get(`${currentEnv}:${env.currentProject}`)
1243
+ );
1244
+ for (const block of blocks)
1245
+ printBlockVersion(
1246
+ this,
1247
+ block,
1248
+ !version
1249
+ ? {
1250
+ showImage: false,
1251
+ showSource: true,
1252
+ showStaticPaths: false,
1253
+ showStatus: false,
1254
+ }
1255
+ : undefined
1256
+ );
1257
+ });
1258
+ }
1259
+
1260
+ if (err) {
1261
+ log.error(messages.blocks.noList(currentEnv, env.currentProject));
1262
+ log.error(jsonFormatter(err));
1263
+ }
1264
+ }
1265
+ };
1266
+
1267
+ PushBlock = async (block: PushBlockParams) => {
1268
+ const { currentEnv, env, log, messages } = this;
1269
+
1270
+ // Output request to console
1271
+ messages.blocks.tryPush(
1272
+ block.id,
1273
+ block.source.branch,
1274
+ currentEnv,
1275
+ env.currentProject
1276
+ );
1277
+ console.log(jsonFormatter(block));
1278
+
1279
+ if (!this.contensis) await this.ConnectContensis();
1280
+ if (this.contensis) {
1281
+ // Push new block version
1282
+ const [err, blockVersion] = await this.contensis.blocks.PushBlockVersion(
1283
+ block
1284
+ );
1285
+ if (!err) {
1286
+ log.success(
1287
+ messages.blocks.pushed(
1288
+ block.id,
1289
+ block.source.branch,
1290
+ currentEnv,
1291
+ env.currentProject
1292
+ )
1293
+ );
1294
+ console.log(jsonFormatter(blockVersion));
1295
+ }
1296
+ if (blockVersion) {
1297
+ this.HandleFormattingAndOutput(blockVersion, () => {
1298
+ // print the version detail to console
1299
+ printBlockVersion(this, blockVersion);
1300
+ });
1301
+ }
1302
+ if (err)
1303
+ throw new Error(
1304
+ messages.blocks.failedPush(block.id, currentEnv, env.currentProject)
1305
+ );
1306
+ }
1307
+ };
1308
+
1309
+ PrintBlockLogs = async (
1310
+ blockId: string,
1311
+ branch: string,
1312
+ version: string,
1313
+ dataCenter: 'hq' | 'manchester' | 'london'
1314
+ ) => {
1315
+ const { currentEnv, log, messages } = this;
1316
+ if (!this.contensis) await this.ConnectContensis();
1317
+ if (this.contensis) {
1318
+ // Retrieve block logs
1319
+ const [err, blockLogs] = await this.contensis.blocks.GetBlockLogs({
1320
+ blockId,
1321
+ branchId: branch,
1322
+ version,
1323
+ dataCenter,
1324
+ });
1325
+
1326
+ if (blockLogs) {
1327
+ this.HandleFormattingAndOutput(blockLogs, () => {
1328
+ // print the logs to console
1329
+ log.success(messages.blocks.list(currentEnv));
1330
+ console.log(
1331
+ ` - ${blockId} ${branch} ${
1332
+ Number(version) ? `v${version}` : version
1333
+ } [${dataCenter}]`
1334
+ );
1335
+ log.line();
1336
+ console.log(log.infoText(blockLogs));
1337
+ log.line();
1338
+ });
1339
+ }
1340
+
1341
+ if (err) {
1342
+ log.error(messages.blocks.noList(currentEnv));
1343
+ log.error(jsonFormatter(err));
1344
+ }
1345
+ }
1346
+ };
1347
+
1348
+ HandleFormattingAndOutput = <T>(obj: T, logFn: (obj: T) => void) => {
1349
+ const { format, log, messages, output } = this;
1350
+ if (output) {
1351
+ let writeString = '';
1352
+ if (format === 'csv') {
1353
+ writeString = csvFormatter(obj as any);
1354
+ } else if (format === 'xml') {
1355
+ writeString = xmlFormatter(obj as any);
1356
+ } else writeString = jsonFormatter(obj);
1357
+ // write output to file
1358
+ if (writeString) {
1359
+ fs.writeFileSync(output, writeString);
1360
+ log.success(messages.app.fileOutput(format, output));
1361
+ } else {
1362
+ log.info(messages.app.noFileOutput());
1363
+ }
1364
+ } else {
1365
+ if (!format) {
1366
+ // print the object to console
1367
+ logFn(obj);
1368
+ } else if (format === 'csv') {
1369
+ log.raw('');
1370
+ log.raw(log.infoText(csvFormatter(obj)));
1371
+ } else if (format === 'xml') {
1372
+ log.raw('');
1373
+ log.raw(log.infoText(xmlFormatter(obj)));
1374
+ } else if (format === 'json') {
1375
+ log.raw('');
1376
+ log.raw(log.infoText(jsonFormatter(obj)));
1377
+ }
1378
+ log.raw('');
1379
+ }
1380
+ };
1381
+ }
1382
+
1383
+ export const cliCommand = (
1384
+ commandArgs: string[],
1385
+ outputOpts: OutputOptions & IConnectOptions = {},
1386
+ contensisOpts: Partial<MigrateRequest> = {}
1387
+ ) => {
1388
+ return new ContensisCli(['', '', ...commandArgs], outputOpts, contensisOpts);
1389
+ };
1390
+ export default ContensisCli;