Skip to content
This repository has been archived by the owner on Feb 27, 2024. It is now read-only.

Commit

Permalink
feat: extends console logging with more data & colors
Browse files Browse the repository at this point in the history
  • Loading branch information
Enngage committed Sep 14, 2022
1 parent 68817d2 commit 9085d8d
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 57 deletions.
4 changes: 3 additions & 1 deletion lib/clean/clean.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AssetFolderModels, ManagementClient } from '@kontent-ai/management-sdk';
import { HttpService } from '@kontent-ai/core-sdk';

import { defaultRetryStrategy, defaultWorkflowCodename, handleError, ItemType } from '../core';
import { defaultRetryStrategy, defaultWorkflowCodename, handleError, ItemType, printProjectInfoToConsoleAsync } from '../core';
import { ICleanConfig, ICleanResult } from './clean.models';

export class CleanService {
Expand All @@ -21,6 +21,8 @@ export class CleanService {

public async cleanAllAsync(): Promise<ICleanResult> {
try {
await printProjectInfoToConsoleAsync(this.client);

await this.cleanContentItemsAsync();
await this.cleanContentTypesAsync();
await this.cleanContentTypeSnippetsAsync();
Expand Down
9 changes: 8 additions & 1 deletion lib/core/global-helper.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { SharedModels } from '@kontent-ai/management-sdk';
import { IManagementClient, SharedModels } from '@kontent-ai/management-sdk';
import { IRetryStrategyOptions } from '@kontent-ai/core-sdk';
import { yellow } from 'colors';

export const defaultRetryStrategy: IRetryStrategyOptions = {
addJitter: true,
Expand All @@ -8,6 +9,12 @@ export const defaultRetryStrategy: IRetryStrategyOptions = {
deltaBackoffMs: 1000
};

export async function printProjectInfoToConsoleAsync(client: IManagementClient<any>): Promise<void> {
const projectInformation = (await client.projectInformation().toPromise()).data;
console.log(`Project '${yellow(projectInformation.project.name)}'`);
console.log(`Environment '${yellow(projectInformation.project.environment)}'\n`);
}

export function getFilenameWithoutExtension(filename: string): string {
if (!filename) {
throw Error(`Invalid filename`);
Expand Down
52 changes: 40 additions & 12 deletions lib/export/export.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ import {
WebhookContracts,
CollectionContracts
} from '@kontent-ai/management-sdk';
import {HttpService } from '@kontent-ai/core-sdk';
import { HttpService } from '@kontent-ai/core-sdk';

import { IExportAllResult, IExportConfig, IExportData } from './export.models';
import { defaultRetryStrategy, ItemType } from '../core';
import { defaultRetryStrategy, ItemType, printProjectInfoToConsoleAsync } from '../core';
import { version } from '../../package.json';
import { green, red, yellow } from 'colors';

export class ExportService {
private readonly client: ManagementClient;
Expand Down Expand Up @@ -53,17 +54,34 @@ export class ExportService {
let projectValidation: string | ProjectContracts.IProjectReportResponseContract;
let isInconsistentExport: boolean = false;

await printProjectInfoToConsoleAsync(this.client);

if (!this.config.skipValidation) {
console.log(green('Running project validation'));
projectValidation = await this.exportProjectValidationAsync();
isInconsistentExport = projectValidation.type_issues.length > 0 || projectValidation.variant_issues.length > 0;
console.log(`Project validation - ${projectValidation.type_issues.length} type issues, ${projectValidation.variant_issues.length} variant issues`);
isInconsistentExport =
projectValidation.type_issues.length > 0 || projectValidation.variant_issues.length > 0;
console.log(
`Project validation results: ${
projectValidation.type_issues.length
? red(projectValidation.type_issues.length.toString())
: green('0')
} type issues, ${
projectValidation.variant_issues.length
? red(projectValidation.variant_issues.length.toString())
: green('0')
} variant issues`
);
console.log('Projects with type or variant issues might not get imported back successfully');
} else {
console.log(red('Skipping project validation'));
projectValidation = '{}';
console.log('Skipping project validation endpoint');
}

const contentTypes = await this.exportContentTypesAsync({ processItem: exportItems.contentType });
console.log();

const contentTypes = await this.exportContentTypesAsync({ processItem: exportItems.contentType });
const languages = await this.exportLanguagesAsync();
const contentItems =
exportItems.contentItem || exportItems.languageVariant ? await this.exportContentItemsAsync() : [];

Expand All @@ -76,10 +94,10 @@ export class ExportService {
contentItems: exportItems.contentItem ? await this.exportContentItemsAsync() : [],
collections: exportItems.collections ? await this.exportCollectionsAsync() : [],
languageVariants: exportItems.languageVariant
? await this.exportLanguageVariantsAsync(contentItems.map((m) => m.id))
? await this.exportLanguageVariantsAsync(contentItems, languages)
: [],
assets: exportItems.asset ? await this.exportAssetsAsync() : [],
languages: exportItems.language ? await this.exportLanguagesAsync() : [],
languages: exportItems.language ? languages : [],
assetFolders: exportItems.assetFolder ? await this.exportAssetFoldersAsync() : []
};

Expand Down Expand Up @@ -208,15 +226,25 @@ export class ExportService {
}

public async exportLanguageVariantsAsync(
contentItemIds: string[]
contentItems: ContentItemContracts.IContentItemModelContract[],
languages: LanguageContracts.ILanguageModelContract[]
): Promise<LanguageVariantContracts.ILanguageVariantModelContract[]> {
const languageVariants: LanguageVariantContracts.ILanguageVariantModelWithComponentsContract[] = [];

for (const contentItemId of contentItemIds) {
const response = await this.client.listLanguageVariantsOfItem().byItemId(contentItemId).toPromise();
for (const contentItem of contentItems) {
const response = await this.client.listLanguageVariantsOfItem().byItemId(contentItem.id).toPromise();

languageVariants.push(...response.data.items.map((m) => m._raw));
response.data.items.forEach((m) => this.processItem(m.item.id?.toString() ?? '-', 'languageVariant', m));

for (const languageVariant of response.data.items) {
const language = languages.find((m) => m.id === languageVariant.language.id);

this.processItem(
`${contentItem.name} (${yellow(language?.name ?? '')})`,
'languageVariant',
languageVariant
);
}
}

return languageVariants;
Expand Down
28 changes: 22 additions & 6 deletions lib/import/import.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ import {
handleError,
defaultWorkflowCodename,
defaultObjectId,
defaultRetryStrategy
defaultRetryStrategy,
printProjectInfoToConsoleAsync
} from '../core';
import { IBinaryFile, IImportConfig, IImportSource } from './import.models';
import { HttpService } from '@kontent-ai/core-sdk';
import { yellow } from 'colors';

export class ImportService {
private readonly defaultLanguageId: string = defaultObjectId;
Expand Down Expand Up @@ -68,6 +70,8 @@ export class ImportService {
sourceData: IImportSource
): Promise<IImportItemResult<ValidImportContract, ValidImportModel>[]> {
const importedItems: IImportItemResult<ValidImportContract, ValidImportModel>[] = [];
await printProjectInfoToConsoleAsync(this.client);

// log information regarding version mismatch
if (version !== sourceData.metadata.version) {
console.warn(
Expand Down Expand Up @@ -344,7 +348,9 @@ export class ImportService {
// activate inactive languages
if (!existingLanguage.isActive) {
console.log(
`Language '${existingLanguage.name}' with codename '${existingLanguage.codename}' is not active in target project. Activating language.`
`Language '${yellow(existingLanguage.name)}' with codename '${yellow(
existingLanguage.codename
)}' is not active in target project. Activating language.`
);

await this.client
Expand All @@ -367,13 +373,17 @@ export class ImportService {

if (!defaultExistingLanguage) {
throw Error(
`Invalid default existing language. Language with id '${importLanguage.id}' was not found.`
`Invalid default existing language. Language with id '${yellow(importLanguage.id)}' was not found.`
);
}
if (importLanguage.codename !== defaultExistingLanguage.codename) {
// languages do not match, change it
console.log(
`Default language '${importLanguage.name}' with codename '${importLanguage.codename}' does not match default language in target project. Changing language codename in target project from '${defaultExistingLanguage.codename}' codename to '${importLanguage.codename}'`
`Default language '${yellow(importLanguage.name)}' with codename '${yellow(
importLanguage.codename
)}' does not match default language in target project. Changing language codename in target project from '${
defaultExistingLanguage.codename
}' codename to '${importLanguage.codename}'`
);

// check if language with imported codename exists
Expand All @@ -392,7 +402,9 @@ export class ImportService {
.toPromise();
} else {
console.log(
`Language with codename '${importLanguage.codename}' already exists in target project, skipping update operation`
`Language with codename '${yellow(
importLanguage.codename
)}' already exists in target project, skipping update operation`
);
}
}
Expand All @@ -408,7 +420,11 @@ export class ImportService {

if (existingLanguage) {
// no need to import it
console.log(`Skipping language '${existingLanguage.name}' with codename '${existingLanguage.codename}'`);
console.log(
`Skipping language '${yellow(existingLanguage.name)}' with codename '${yellow(
existingLanguage.codename
)}'`
);
return 'noImport';
}

Expand Down
34 changes: 11 additions & 23 deletions lib/node/cli/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ZipService } from '../../zip';
import { SharedModels } from '@kontent-ai/management-sdk';
import { FileService } from '../file/file.service';
import { fileHelper } from '../file/file-helper';
import { green, red, yellow } from 'colors';

const argv = yargs(process.argv.slice(2))
.example('kbm --action=backup --apiKey=xxx --projectId=xxx', 'Creates zip backup of Kontent.ai project')
Expand Down Expand Up @@ -41,10 +42,7 @@ const argv = yargs(process.argv.slice(2))
.alias('b', 'baseUrl')
.describe('b', 'Custom base URL for Management API calls.')
.alias('s', 'preserveWorkflow')
.describe(
's',
'Indicates if workflow information of language variants is preserved'
)
.describe('s', 'Indicates if workflow information of language variants is preserved')
.alias('e', 'exportFilter')
.describe(
'e',
Expand All @@ -62,7 +60,7 @@ const backupAsync = async (config: ICliFileConfig) => {
skipValidation: config.skipValidation ?? false,
onExport: (item) => {
if (config.enableLog) {
console.log(`Exported: ${item.title} | ${item.type}`);
console.log(`Exported ${yellow(item.title)} (${green(item.type)})`);
}
}
});
Expand All @@ -77,21 +75,11 @@ const backupAsync = async (config: ICliFileConfig) => {
});

const response = await exportService.exportAllAsync();

if (response.metadata.isInconsistentExport) {
const logFilename: string = getLogFilename(config.zipFilename);

console.log(`Project contains inconsistencies which may cause errors during project import.`);
console.log(`See '${logFilename}' for more details.`);
} else {
console.log(`Project does not contain any inconsistencies`);
}

const zipFileData = await zipService.createZipAsync(response);

await fileService.writeFileAsync(config.zipFilename, zipFileData);

console.log('Completed');
console.log(green('Completed'));
};

const getLogFilename = (filename: string) => {
Expand All @@ -102,7 +90,7 @@ const cleanAsync = async (config: ICliFileConfig) => {
const cleanService = new CleanService({
onDelete: (item) => {
if (config.enableLog) {
console.log(`Deleted: ${item.title} | ${item.type}`);
console.log(`Deleted: ${yellow(item.title)}`);
}
},
baseUrl: config.baseUrl,
Expand All @@ -112,7 +100,7 @@ const cleanAsync = async (config: ICliFileConfig) => {

await cleanService.cleanAllAsync();

console.log('Completed');
console.log(green('Completed'));
};

const restoreAsync = async (config: ICliFileConfig) => {
Expand All @@ -128,7 +116,7 @@ const restoreAsync = async (config: ICliFileConfig) => {
const importService = new ImportService({
onImport: (item) => {
if (config.enableLog) {
console.log(`Imported: ${item.title} | ${item.type}`);
console.log(`Imported: ${yellow(item.title)} (${green(item.type)})`);
}
},
preserveWorkflow: config.preserveWorkflow,
Expand All @@ -152,14 +140,14 @@ const restoreAsync = async (config: ICliFileConfig) => {
if (canImport(data, config)) {
await importService.importFromSourceAsync(data);

console.log('Completed');
console.log(green('Completed'));
} else {
const logFilename: string = getLogFilename(config.zipFilename);

await fileHelper.createFileInCurrentFolderAsync(logFilename, JSON.stringify(data.validation));

console.log(`Project could not be imported due to data inconsistencies.`);
console.log(`A log file '${logFilename}' with issues was created in current folder.`);
console.log(`A log file '${yellow(logFilename)}' with issues was created in current folder.`);
console.log(`To import data regardless of issues, set 'force' config parameter to true`);
}
};
Expand Down Expand Up @@ -286,11 +274,11 @@ run()
.then((m) => {})
.catch((err) => {
if (err instanceof SharedModels.ContentManagementBaseKontentError) {
console.log(`Management API error occured:`, err.message);
console.log(`Management API error occured:`, red(err.message));
for (const validationError of err.validationErrors) {
console.log(validationError.message);
}
} else {
console.log(`There was an error processing your request: `, err);
console.log(`There was an error processing your request: `, red(err));
}
});
13 changes: 5 additions & 8 deletions lib/node/file/file.service.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import { yellow } from 'colors';
import { promises } from 'fs';
import { IFileServiceConfig } from './file.models';

export class FileService {

constructor(private config: IFileServiceConfig) {
}
constructor(private config: IFileServiceConfig) {}

private readonly zipExtension: string = '.zip';


async loadFileAsync(fileNameWithoutExtension: string): Promise<Buffer> {
const filePath = this.getFilePath(fileNameWithoutExtension);

if (this.config.enableLog) {
console.log(`Reading file '${filePath}'`);
console.log(`Reading file '${yellow(filePath)}'`);
}
const file = await promises.readFile(filePath);
if (this.config.enableLog) {
Expand All @@ -27,7 +25,7 @@ export class FileService {
const filePath = this.getFilePath(fileNameWithoutExtension);

if (this.config.enableLog) {
console.log(`Writing file '${filePath}'`);
console.log(`Writing file '${yellow(filePath)}'`);
}
await promises.writeFile(filePath, content);
if (this.config.enableLog) {
Expand All @@ -37,7 +35,6 @@ export class FileService {

private getFilePath(fileNameWithoutExtension: string) {
const filenameWithExtension = fileNameWithoutExtension + this.zipExtension;
return`./${filenameWithExtension}`;
return `./${filenameWithExtension}`;
}

}
Loading

0 comments on commit 9085d8d

Please sign in to comment.