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

Commit

Permalink
feat: updates all dependencies, uses environment instead of project n…
Browse files Browse the repository at this point in the history
…aming convetion, migrates to eslint, removes obsolete project validation
  • Loading branch information
Enngage committed Jul 31, 2023
1 parent 12c6853 commit 05f1270
Show file tree
Hide file tree
Showing 20 changed files with 4,089 additions and 5,006 deletions.
16 changes: 16 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* eslint-env node */
module.exports = {
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
parserOptions: {
tsconfigRootDir: __dirname,
project: ['./tsconfig.json']
},
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/no-namespace': 'off'
},
root: true
};
23 changes: 11 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@ Install package globally:

| Config | Value |
|-----------------|---------------------------------------------------------------------------------------------------------------------|
| **projectId** | Id of Kontent.ai project **(required)** |
| **environmentId** | Id of Kontent.ai project **(required)** |
| **apiKey** | Content management Api key **(required)** |
| **action** | Action. Possible values are: `restore` & `backup` & `clean` **(required)** |
| zipFilename | Name of zip used for export / restoring data. (e.g. 'kontent-backup'). |
| enableLog | Indicates if default logging is enabled (useful to indicate progress)
| skipValidation | Skips validation endpoint during project export
| force | If enabled, project will we exported / restored even if there are data inconsistencies. Enabled by default. |
| baseUrl | Custom base URL for Management API calls. |
| preserveWorkflow | Indicates language variant workflow information should be preserved |
Expand All @@ -48,15 +47,15 @@ Install package globally:
To backup a project run:

`kbm --action=backup --apiKey=xxx --projectId=xxx`
`kbm --action=backup --apiKey=xxx --environmentId=xxx`

To restore a project run:

`kbm --action=restore --apiKey=xxx --projectId=xxx --zipFilename=backupFile`
`kbm --action=restore --apiKey=xxx --environmentId=xxx --zipFilename=backupFile`

To clean (delete) everything inside a project run:

`kbm --action=clean --apiKey=xxx --projectId=xxx`
`kbm --action=clean --apiKey=xxx --environmentId=xxx`

To get some help you can use:

Expand All @@ -68,7 +67,7 @@ Create a `json` configuration file in the folder where you are attempting to run

```json
{
"projectId": "xxx",
"environmentId": "xxx",
"apiKey": "xxx",
"zipFilename": "backup",
"action": "backup",
Expand All @@ -94,7 +93,7 @@ import { FileService } from '@kontent-ai/backup-manager/dist/cjs/lib/node';
const run = async () => {
const exportService = new ExportService({
apiKey: 'sourceProjectApiKey',
projectId: 'sourceProjectId',
environmentId: 'sourceEnvironmentId',
exportFilter: undefined,
onExport: item => {
// called when any content is exported
Expand Down Expand Up @@ -167,8 +166,8 @@ const run = async () => {
taxonomy: item => true,// all taxonomies will be imported
},
preserveWorkflow: true, // when enabled, language variants will preserve their workflow information
projectId: 'targetProjectId',
apiKey: 'targetProjectId',
environmentId: 'targetEnvironmentId',
apiKey: 'targetEnvironmentId',
enableLog: true, // shows progress of immport in console
fixLanguages: true, // backup manager will attempt to create missing languages & map existing languages
workflowIdForImportedItems: '00000000-0000-0000-0000-000000000000' // id that items are assigned
Expand Down Expand Up @@ -200,8 +199,8 @@ const run = async () => {
console.log(`Deleted: ${item.title} | ${item.type}`);
},
fixLanguages: true,
projectId: 'targetProjectId',
apiKey: 'targetProjectId',
environmentId: 'targetEnvironmentId',
apiKey: 'targetEnvironmentId',
enableLog: true
});

Expand All @@ -224,5 +223,5 @@ The Node.js limits the maximum header size of HTTP requests. In some cases it ma
Example script call:

```
node --max-http-header-size 150000 %USERPROFILE%\AppData\Roaming\npm\node_modules\@kontent-ai\backup-manager\dist\cjs\lib\node\cli\app --action=backup --apiKey=<key> --projectId=<projectId>
node --max-http-header-size 150000 %USERPROFILE%\AppData\Roaming\npm\node_modules\@kontent-ai\backup-manager\dist\cjs\lib\node\cli\app --action=backup --apiKey=<key> --environmentId=<environmentId>
```
4 changes: 2 additions & 2 deletions lib/clean/clean.models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { IProcessedItem } from '../core';
import { IRetryStrategyOptions } from '@kontent-ai/core-sdk';

export interface ICleanConfig {
projectId: string;
environmentId: string;
apiKey: string;
baseUrl?: string;
onDelete?: (item: IProcessedItem) => void;
Expand All @@ -12,6 +12,6 @@ export interface ICleanConfig {
export interface ICleanResult {
metadata: {
timestamp: Date,
projectId: string;
environmentId: string;
};
}
46 changes: 24 additions & 22 deletions lib/clean/clean.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { AssetFolderModels, ManagementClient } from '@kontent-ai/management-sdk';
import { HttpService } from '@kontent-ai/core-sdk';

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

export class CleanService {
Expand All @@ -10,7 +16,7 @@ export class CleanService {
constructor(private config: ICleanConfig) {
this.client = new ManagementClient({
apiKey: config.apiKey,
projectId: config.projectId,
environmentId: config.environmentId,
baseUrl: config.baseUrl,
httpService: new HttpService({
logErrorsToConsole: false
Expand All @@ -20,26 +26,22 @@ export class CleanService {
}

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

await this.cleanContentItemsAsync();
await this.cleanContentTypesAsync();
await this.cleanContentTypeSnippetsAsync();
await this.cleanTaxonomiesAsync();
await this.cleanAssetsAsync();
await this.cleanAssetFoldersAsync();
await this.cleanWorkflowsAsync();

return {
metadata: {
projectId: this.config.projectId,
timestamp: new Date()
}
};
} catch (err) {
throw err;
}
await printProjectInfoToConsoleAsync(this.client);

await this.cleanContentItemsAsync();
await this.cleanContentTypesAsync();
await this.cleanContentTypeSnippetsAsync();
await this.cleanTaxonomiesAsync();
await this.cleanAssetsAsync();
await this.cleanAssetFoldersAsync();
await this.cleanWorkflowsAsync();

return {
metadata: {
environmentId: this.config.environmentId,
timestamp: new Date()
}
};
}

public async cleanWorkflowsAsync(): Promise<void> {
Expand Down
6 changes: 2 additions & 4 deletions lib/core/core.models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
} from '@kontent-ai/management-sdk';

export interface ICliFileConfig {
projectId: string;
environmentId: string;
apiKey: string;
action: CliAction;
zipFilename: string;
Expand All @@ -29,7 +29,6 @@ export interface ICliFileConfig {
force: boolean;
baseUrl?: string;
exportFilter?: ItemType[];
skipValidation?: boolean;
}

export type CliAction = 'backup' | 'restore' | 'clean';
Expand Down Expand Up @@ -92,9 +91,8 @@ export interface IIdCodenameTranslationResult {

export interface IPackageMetadata {
version: string;
projectId: string;
environmentId: string;
timestamp: Date;
isInconsistentExport: boolean;
dataOverview: IPackageDataOverview;
}

Expand Down
11 changes: 5 additions & 6 deletions lib/core/global-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ export const defaultRetryStrategy: IRetryStrategyOptions = {
};

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`);
const environmentInfo = (await client.environmentInformation().toPromise()).data;
console.log(`Project '${yellow(environmentInfo.project.name)}'`);
console.log(`Environment '${yellow(environmentInfo.project.environment)}'\n`);
}

export function getFilenameWithoutExtension(filename: string): string {
Expand All @@ -28,14 +28,13 @@ export function getFilenameWithoutExtension(filename: string): string {
}

export function handleError(error: any | SharedModels.ContentManagementBaseKontentError): void {
let result = error;
if (error instanceof SharedModels.ContentManagementBaseKontentError) {
result = {
throw {
Message: `Failed to import data with error: ${error.message}`,
ErrorCode: error.errorCode,
RequestId: error.requestId,
ValidationErrors: `${error.validationErrors.map((m) => m.message).join(', ')}`
};
}
throw result;
throw error;
}
8 changes: 4 additions & 4 deletions lib/core/id-translate-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ export class IdTranslateHelper {
text: string,
items: IImportItemResult<ValidImportContract, ValidImportModel>[]
): string {
const itemId = { regex: /data-item-id=\"(.*?)\"/g, attr: 'data-item-id' };
const assetId = { regex: /data-asset-id=\"(.*?)\"/g, attr: 'data-asset-id' };
const imageId = { regex: /data-image-id=\"(.*?)\"/g, attr: 'data-image-id' };
const dataId = { regex: /data-id=\"(.*?)\"/g, attr: 'data-id' };
const itemId = { regex: /data-item-id="(.*?)"/g, attr: 'data-item-id' };
const assetId = { regex: /data-asset-id="(.*?)"/g, attr: 'data-asset-id' };
const imageId = { regex: /data-image-id="(.*?)"/g, attr: 'data-image-id' };
const dataId = { regex: /data-id="(.*?)"/g, attr: 'data-id' };

text = this.replaceTextWithRegex(itemId.regex, text, itemId.attr, items);
text = this.replaceTextWithRegex(assetId.regex, text, assetId.attr, items);
Expand Down
5 changes: 1 addition & 4 deletions lib/export/export.models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
LanguageContracts,
LanguageVariantContracts,
TaxonomyContracts,
ProjectContracts,
WorkflowContracts,
WebhookContracts,
CollectionContracts
Expand All @@ -17,12 +16,11 @@ import { IRetryStrategyOptions } from '@kontent-ai/core-sdk';
import { IProcessedItem, IPackageMetadata, ItemType } from '../core';

export interface IExportConfig {
projectId: string;
environmentId: string;
apiKey: string;
baseUrl?: string;
onExport?: (item: IProcessedItem) => void;
exportFilter?: ItemType[];
skipValidation: boolean;
retryStrategy?: IRetryStrategyOptions;
}

Expand All @@ -43,5 +41,4 @@ export interface IExportData {
export interface IExportAllResult {
metadata: IPackageMetadata;
data: IExportData;
validation: ProjectContracts.IProjectReportResponseContract | string;
}
40 changes: 3 additions & 37 deletions lib/export/export.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
AssetContracts,
LanguageContracts,
AssetFolderContracts,
ProjectContracts,
WorkflowContracts,
WebhookContracts,
CollectionContracts
Expand All @@ -18,15 +17,15 @@ import { HttpService } from '@kontent-ai/core-sdk';
import { IExportAllResult, IExportConfig, IExportData } from './export.models';
import { defaultRetryStrategy, ItemType, printProjectInfoToConsoleAsync } from '../core';
import { version } from '../../package.json';
import { green, red, yellow } from 'colors';
import { yellow } from 'colors';

export class ExportService {
private readonly client: ManagementClient;

constructor(private config: IExportConfig) {
this.client = new ManagementClient({
apiKey: config.apiKey,
projectId: config.projectId,
environmentId: config.environmentId,
baseUrl: config.baseUrl,
httpService: new HttpService({
logErrorsToConsole: false
Expand All @@ -51,33 +50,8 @@ export class ExportService {
workflows: this.config.exportFilter?.includes('workflow') ?? true
};

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 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();

const contentTypes = await this.exportContentTypesAsync({ processItem: exportItems.contentType });
Expand Down Expand Up @@ -105,8 +79,7 @@ export class ExportService {
metadata: {
version,
timestamp: new Date(),
projectId: this.config.projectId,
isInconsistentExport,
environmentId: this.config.environmentId,
dataOverview: {
assetFoldersCount: data.assetFolders.length,
assetsCount: data.assets.length,
Expand All @@ -121,16 +94,9 @@ export class ExportService {
collectionsCount: data.collections.length
}
},
validation: projectValidation,
data
};
}

public async exportProjectValidationAsync(): Promise<ProjectContracts.IProjectReportResponseContract> {
const response = await this.client.validateProjectContent().projectId(this.config.projectId).toPromise();
return response.rawData;
}

public async exportAssetsAsync(): Promise<AssetContracts.IAssetModelContract[]> {
const response = await this.client
.listAssets()
Expand Down
Loading

0 comments on commit 05f1270

Please sign in to comment.