@dxdeveloperexperience/hygie
Version:
Hygie is an easy-to-use Open-Source REST API allowing you to interact with GIT events. This NestJS API expose a set of customizable rules to automate your project's life cycle.
189 lines (163 loc) • 5.97 kB
text/typescript
import { Injectable } from '@nestjs/common';
import { Rule } from './rule.class';
import { RunnablesService } from '../runnables/runnables.service';
import { Webhook } from '../webhook/webhook';
import { RuleResult } from './ruleResult';
import { RulesOptions } from './rules.options';
import { Group } from './group.class';
import { logger } from '../logger/logger.service';
import { GroupResult } from './groupResult';
import { DataAccessService } from '../data_access/dataAccess.service';
import { Utils } from '../utils/utils';
()
export class RulesService {
constructor(
private readonly runnableService: RunnablesService,
private readonly dataAccessService: DataAccessService,
private readonly rulesClasses: Rule[] = [],
) {}
async getConfiguration(
remoteRepository: string,
ruleFile: string,
): Promise<any> {
return await Utils.parseYAMLFile(
await this.dataAccessService.readRule(`${remoteRepository}/${ruleFile}`),
);
}
getRulesConfiguration(configuration: any): Rule[] {
return configuration.rules || [];
}
getGroupsConfiguration(configuration: any): Group[] {
const groupsConfig = configuration.groups || [];
return groupsConfig.map(g => {
const group = new Group();
group.groupName = g.groupName;
group.onError = g.onError || [];
group.onSuccess = g.onSuccess || [];
group.onBoth = g.onBoth || [];
group.rules = g.rules;
return group;
});
}
getRulesOptions(configuration: any): RulesOptions {
return new RulesOptions(configuration.options);
}
getRule(ruleConfig): Rule {
return this.rulesClasses.find(r => r.name === ruleConfig.name);
}
async testRules(
webhook: Webhook,
remoteRepository: string,
ruleFile: string,
): Promise<RuleResult[]> {
const configuration = await this.getConfiguration(
remoteRepository,
ruleFile,
);
const rules: Rule[] = this.getRulesConfiguration(configuration);
const groups: Group[] = this.getGroupsConfiguration(configuration);
const rulesOptions: RulesOptions = this.getRulesOptions(configuration);
const BreakException = {};
const results: RuleResult[] = new Array();
// Individual rules
if (rulesOptions.enableRules) {
try {
logger.info('### TRY RULES ###', {
project: webhook.getCloneURL(),
});
for (let index = 0; index < rules.length; index++) {
// Need a for loop because Async/Wait does not work in ForEach
const ruleConfig = rules[index];
const r = this.getRule(ruleConfig);
if (r.isEnabled(webhook, ruleConfig)) {
const ruleResult: RuleResult = await r.validate(
webhook,
ruleConfig,
results,
);
// Some rules return `null` when there are enabled but ignored due to interne business rule
if (ruleResult !== null) {
results.push(ruleResult);
this.runnableService
.executeRunnableFunctions(ruleResult, ruleConfig)
.catch(err => logger.error(err));
if (!rulesOptions.executeAllRules && !ruleResult.validated) {
throw BreakException;
}
}
}
}
} catch (e) {
if (e !== BreakException) {
logger.error(e, {
project: webhook.getCloneURL(),
location: 'RulesService',
});
}
}
}
// Grouped rules
if (rulesOptions.enableGroups) {
try {
logger.info('### TRY GROUPS ###', {
project: webhook.getCloneURL(),
});
for (let indexGroup = 0; indexGroup < groups.length; indexGroup++) {
// Need a for loop because Async/Wait does not work in ForEach
const g = groups[indexGroup];
const groupResults: GroupResult[] = new Array();
for (let indexRules = 0; indexRules < g.rules.length; indexRules++) {
// Need a for loop because Async/Wait does not work in ForEach
const ruleConfig = g.rules[indexRules];
const r = this.getRule(ruleConfig);
if (r.isEnabled(webhook, ruleConfig)) {
const ruleResult: RuleResult = await r.validate(
webhook,
ruleConfig,
);
// Some rules return `null` when there are enabled but ignored due to interne business rule
if (ruleResult !== null) {
results.push(ruleResult);
if (rulesOptions.allRuleResultInOne) {
groupResults.push({
name: ruleConfig.name,
ruleResult,
});
} else {
this.runnableService
.executeRunnableFunctions(ruleResult, g)
.catch(err => logger.error(err));
}
if (
!rulesOptions.executeAllRules &&
!rulesOptions.allRuleResultInOne &&
!ruleResult.validated
) {
throw BreakException;
}
}
}
}
// If all rules have been tested, we can execute runnable functions with the result of previous rules
if (rulesOptions.allRuleResultInOne) {
if (groupResults.length > 0) {
const ruleResult: RuleResult = new RuleResult(
webhook.getGitApiInfos(),
);
ruleResult.data = groupResults;
this.runnableService
.executeRunnableFunctions(ruleResult, g)
.catch(err => logger.error(err));
}
}
}
} catch (e) {
logger.error(e, {
project: webhook.getCloneURL(),
location: 'RulesService',
});
}
}
return results;
}
}