Skip to content

Commit

Permalink
Merge pull request #956 from contentstack/feat/CS-39984
Browse files Browse the repository at this point in the history
Workflows export & import rewrite and export unit test cases fix
  • Loading branch information
aman19K authored Aug 1, 2023
2 parents 68b71bc + 184ba2b commit 67d0729
Show file tree
Hide file tree
Showing 9 changed files with 391 additions and 40 deletions.
1 change: 1 addition & 0 deletions packages/contentstack-export/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ const config: DefaultConfig = {
'global-fields',
'content-types',
'entries',
'workflows'
],
apis: {
userSession: '/user-session/',
Expand Down
100 changes: 100 additions & 0 deletions packages/contentstack-export/src/export/modules/workflows.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import omit from 'lodash/omit';
import isEmpty from 'lodash/isEmpty';
import { resolve as pResolve } from 'node:path';

import config from '../../config';
import BaseClass from './base-class';
import { log, formatError, fsUtil } from '../../utils';
import { WorkflowConfig, ModuleClassParams } from '../../types';

export default class ExportWorkFlows extends BaseClass {
private workflows: Record<string, Record<string, string>>;
private workflowConfig: WorkflowConfig;
public webhooksFolderPath: string;
private qs: {
include_count: boolean;
skip?: number;
};

constructor({ exportConfig, stackAPIClient }: ModuleClassParams) {
super({ exportConfig, stackAPIClient });
this.workflows = {};
this.workflowConfig = config.modules.workflows;
this.qs = { include_count: true };
}

async start(): Promise<void> {
log(this.exportConfig, 'Starting workflows export', 'info');

this.webhooksFolderPath = pResolve(
this.exportConfig.data,
this.exportConfig.branchName || '',
this.workflowConfig.dirName,
);

await fsUtil.makeDirectory(this.webhooksFolderPath);
await this.getWorkflows();

if (this.workflows === undefined || isEmpty(this.workflows)) {
log(this.exportConfig, 'No workflows found', 'info');
} else {
fsUtil.writeFile(pResolve(this.webhooksFolderPath, this.workflowConfig.fileName), this.workflows);
log(this.exportConfig, 'All the workflows have been exported successfully!', 'success');
}
}

async getWorkflows(skip = 0): Promise<void> {
if (skip) {
this.qs.skip = skip;
}

await this.stack
.workflow()
.fetchAll(this.qs)
.then(async (data: any) => {
const { items, count } = data;
if (items?.length) {
await this.sanitizeAttribs(items);
skip += this.workflowConfig.limit || 100;
if (skip >= count) {
return;
}
return await this.getWorkflows(skip);
}
})
.catch(({ error }: any) => {
log(this.exportConfig, `Failed to export workflows.${formatError(error)}`, 'error');
log(this.exportConfig, error, 'error');
});
}

async sanitizeAttribs(workflows: Record<string, string>[]) {
for (let index = 0; index < workflows?.length; index++) {
await this.getWorkflowRoles(workflows[index]);
const workflowUid = workflows[index].uid;
const workflowName = workflows[index]?.name || '';
this.workflows[workflowUid] = omit(workflows[index], this.workflowConfig.invalidKeys);
log(this.exportConfig, `'${workflowName}' workflow was exported successfully`, 'success');
}
}

async getWorkflowRoles(workflow: Record<string, any>) {
for (const stage of workflow?.workflow_stages) {
for (let i = 0; i < stage?.SYS_ACL?.roles?.uids?.length; i++) {
const roleUid = stage.SYS_ACL.roles.uids[i];
const roleData = await this.getRoles(roleUid);
stage.SYS_ACL.roles.uids[i] = roleData;
}
}
}

async getRoles(roleUid: number): Promise<any> {
return await this.stack
.role(roleUid)
.fetch({ include_rules: true, include_permissions: true })
.then((data: any) => data)
.catch((err: any) =>
log(this.exportConfig, `Failed to fetch roles.${formatError(err)}`, 'error'),
);
}
}
16 changes: 8 additions & 8 deletions packages/contentstack-export/test/integration/assets.test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
let defaultConfig = require('../../src/config/default');
const fs = require('fs');
const path = require('path');
const uniqBy = require('lodash/uniqBy');
const { test } = require('@oclif/test');
const { cliux: cliUX, messageHandler } = require('@contentstack/cli-utilities');

const { default: config } = require('../../src/config');
const { default: config } = require('../../lib/config');
const modules = config.modules;
const { getStackDetailsByRegion, getAssetAndFolderCount, cleanUp, checkCounts } = require('./utils/helper');
const { EXPORT_PATH, DEFAULT_TIMEOUT } = require('./config.json');
Expand All @@ -29,11 +28,12 @@ module.exports = (region) => {
describe('cm:stacks:export assets [auth-token]', () => {
test
.timeout(DEFAULT_TIMEOUT || 600000) // NOTE setting default timeout as 10 minutes
.stub(cliUX, 'prompt', async (name) => {
.stub(cliUX, 'inquire', async (input) => {
const { name } = input;
switch (name) {
case promptMessageList.promptSourceStack:
case 'apiKey':
return stackDetails[stack].STACK_API_KEY;
case promptMessageList.promptPathStoredData:
case 'dir':
return `${EXPORT_PATH}_${stack}`;
}
})
Expand Down Expand Up @@ -105,9 +105,9 @@ module.exports = (region) => {

afterEach(async () => {
await cleanUp(path.join(__dirname, '..', '..', `${EXPORT_PATH}_${stack}`));
defaultConfig.management_token = undefined;
defaultConfig.branch = undefined;
defaultConfig.branches = [];
config.management_token = undefined;
config.branch = undefined;
config.branches = [];
});
}
};
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
let defaultConfig = require('../../src/config/default');
const fs = require('fs');
const { promises: fsPromises } = fs;
const path = require('path');
const { test } = require('@oclif/test');
const { cliux: cliUX, messageHandler } = require('@contentstack/cli-utilities');

const { default: config } = require('../../src/config');
const { default: config } = require('../../lib/config');
const modules = config.modules;
const { getStackDetailsByRegion, getContentTypesCount, cleanUp, checkCounts } = require('./utils/helper');
const { EXPORT_PATH, DEFAULT_TIMEOUT } = require('./config.json');
Expand All @@ -28,11 +27,12 @@ module.exports = (region) => {
describe('cm:stacks:export content-types [auth-token]', () => {
test
.timeout(DEFAULT_TIMEOUT || 600000) // NOTE setting default timeout as 10 minutes
.stub(cliUX, 'prompt', async (name) => {
.stub(cliUX, 'inquire', async (input) => {
const { name } = input;
switch (name) {
case promptMessageList.promptSourceStack:
case 'apiKey':
return stackDetails[stack].STACK_API_KEY;
case promptMessageList.promptPathStoredData:
case 'dir':
return `${EXPORT_PATH}_${stack}`;
}
})
Expand Down Expand Up @@ -92,9 +92,9 @@ module.exports = (region) => {

afterEach(async () => {
await cleanUp(path.join(__dirname, '..', '..', `${EXPORT_PATH}_${stack}`));
defaultConfig.management_token = undefined;
defaultConfig.branch = undefined;
defaultConfig.branches = [];
config.management_token = undefined;
config.branch = undefined;
config.branches = [];
});
}
};
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
let defaultConfig = require('../../src/config/default');
const fs = require('fs');
const path = require('path');
const { test } = require('@oclif/test');
const { cliux: cliUX, messageHandler } = require('@contentstack/cli-utilities');

const { default: config } = require('../../src/config');
const { default: config } = require('../../lib/config');
const modules = config.modules;
const { getStackDetailsByRegion, getCustomRolesCount, cleanUp, checkCounts } = require('./utils/helper');
const { EXPORT_PATH, DEFAULT_TIMEOUT } = require('./config.json');
Expand All @@ -27,11 +26,12 @@ module.exports = (region) => {
describe('cm:stacks:export custom-roles [auth-token]', () => {
test
.timeout(DEFAULT_TIMEOUT || 600000) // NOTE setting default timeout as 10 minutes
.stub(cliUX, 'prompt', async (name) => {
.stub(cliUX, 'inquire', async (input) => {
const { name } = input;
switch (name) {
case promptMessageList.promptSourceStack:
case 'apiKey':
return stackDetails[stack].STACK_API_KEY;
case promptMessageList.promptPathStoredData:
case 'dir':
return `${EXPORT_PATH}_${stack}`;
}
})
Expand Down Expand Up @@ -86,9 +86,9 @@ module.exports = (region) => {

afterEach(async () => {
await cleanUp(path.join(__dirname, '..', '..', `${EXPORT_PATH}_${stack}`));
defaultConfig.management_token = undefined;
defaultConfig.branch = undefined;
defaultConfig.branches = [];
config.management_token = undefined;
config.branch = undefined;
config.branches = [];
});
}
};
16 changes: 8 additions & 8 deletions packages/contentstack-export/test/integration/labels.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
let defaultConfig = require('../../src/config/default');
const fs = require('fs');
const path = require('path');
const { test } = require('@oclif/test');
const { cliux: cliUX, messageHandler } = require('@contentstack/cli-utilities');

const { default: config } = require('../../src/config');
const { default: config } = require('../../lib/config');
const modules = config.modules;
const { getStackDetailsByRegion, getLabelsCount, cleanUp, checkCounts } = require('./utils/helper');
const { EXPORT_PATH, DEFAULT_TIMEOUT } = require('./config.json');
Expand All @@ -27,11 +26,12 @@ module.exports = (region) => {
describe('cm:stacks:export labels [auth-token]', () => {
test
.timeout(DEFAULT_TIMEOUT || 600000) // NOTE setting default timeout as 10 minutes
.stub(cliUX, 'prompt', async (name) => {
.stub(cliUX, 'inquire', async (input) => {
const { name } = input;
switch (name) {
case promptMessageList.promptSourceStack:
case 'apiKey':
return stackDetails[stack].STACK_API_KEY;
case promptMessageList.promptPathStoredData:
case 'dir':
return `${EXPORT_PATH}_${stack}`;
}
})
Expand Down Expand Up @@ -85,9 +85,9 @@ module.exports = (region) => {

afterEach(async () => {
await cleanUp(path.join(__dirname, '..', '..', `${EXPORT_PATH}_${stack}`));
defaultConfig.management_token = undefined;
defaultConfig.branch = undefined;
defaultConfig.branches = [];
config.management_token = undefined;
config.branch = undefined;
config.branches = [];
});
}
};
16 changes: 8 additions & 8 deletions packages/contentstack-export/test/integration/locales.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
let defaultConfig = require('../../src/config/default');
const fs = require('fs');
const path = require('path');
const { test } = require('@oclif/test');
const { cliux: cliUX, messageHandler } = require('@contentstack/cli-utilities');

const { default: config } = require('../../src/config');
const { default: config } = require('../../lib/config');
const modules = config.modules;
const { getStackDetailsByRegion, getLocalesCount, cleanUp, checkCounts } = require('./utils/helper');
const { EXPORT_PATH, DEFAULT_TIMEOUT } = require('./config.json');
Expand All @@ -27,11 +26,12 @@ module.exports = (region) => {
describe('cm:stacks:export locales [auth-token]', () => {
test
.timeout(DEFAULT_TIMEOUT || 600000) // NOTE setting default timeout as 10 minutes
.stub(cliUX, 'prompt', async (name) => {
.stub(cliUX, 'inquire', async (input) => {
const { name } = input;
switch (name) {
case promptMessageList.promptSourceStack:
case 'apiKey':
return stackDetails[stack].STACK_API_KEY;
case promptMessageList.promptPathStoredData:
case 'dir':
return `${EXPORT_PATH}_${stack}`;
}
})
Expand Down Expand Up @@ -87,9 +87,9 @@ module.exports = (region) => {

afterEach(async () => {
await cleanUp(path.join(__dirname, '..', '..', `${EXPORT_PATH}_${stack}`));
defaultConfig.management_token = undefined;
defaultConfig.branch = undefined;
defaultConfig.branches = [];
config.management_token = undefined;
config.branch = undefined;
config.branches = [];
});
}
};
1 change: 1 addition & 0 deletions packages/contentstack-import/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ const config: DefaultConfig = {
'content-types',
'webhooks',
'custom-roles',
'workflows'
],
rateLimit: 5,
preserveStackVersion: false,
Expand Down
Loading

0 comments on commit 67d0729

Please sign in to comment.