feat: count errors, improve error messaging
This commit is contained in:
parent
5e05c72b7e
commit
f50f2f13f8
13
Makefile
13
Makefile
|
@ -42,7 +42,7 @@ RELEASE_OPTS ?= --commit-all
|
||||||
export NODE_VERSION := $(shell node -v)
|
export NODE_VERSION := $(shell node -v)
|
||||||
export RUNNER_VERSION := $(CI_RUNNER_VERSION)
|
export RUNNER_VERSION := $(CI_RUNNER_VERSION)
|
||||||
|
|
||||||
all: build run-terminal
|
all: build
|
||||||
|
|
||||||
clean: ## clean up the target directory
|
clean: ## clean up the target directory
|
||||||
rm -rf node_modules
|
rm -rf node_modules
|
||||||
|
@ -74,16 +74,7 @@ todo:
|
||||||
|
|
||||||
# build targets
|
# build targets
|
||||||
build: ## builds, bundles, and tests the application
|
build: ## builds, bundles, and tests the application
|
||||||
build: build-fast
|
build: bundle
|
||||||
|
|
||||||
build-cover: ## builds, bundles, and tests the application with code coverage
|
|
||||||
build-cover: configure node_modules
|
|
||||||
|
|
||||||
build-fast: ## builds, bundles, and tests the application
|
|
||||||
build-fast: configure node_modules
|
|
||||||
|
|
||||||
build-strict: ## builds, bundles, and tests the application with type checks and extra warnings (slow)
|
|
||||||
build-strict: configure node_modules
|
|
||||||
|
|
||||||
bundle: node_modules
|
bundle: node_modules
|
||||||
$(NODE_BIN)/rollup --config $(CONFIG_PATH)/rollup.js
|
$(NODE_BIN)/rollup --config $(CONFIG_PATH)/rollup.js
|
||||||
|
|
24
src/index.ts
24
src/index.ts
|
@ -12,6 +12,7 @@ const CONFIG_ARGS_PATH = 'config-path';
|
||||||
|
|
||||||
const MAIN_ARGS: Options = {
|
const MAIN_ARGS: Options = {
|
||||||
alias: {
|
alias: {
|
||||||
|
'count': ['c'],
|
||||||
'includeTag': ['t', 'tag'],
|
'includeTag': ['t', 'tag'],
|
||||||
'mode': ['m'],
|
'mode': ['m'],
|
||||||
},
|
},
|
||||||
|
@ -25,10 +26,14 @@ const MAIN_ARGS: Options = {
|
||||||
'includeTag',
|
'includeTag',
|
||||||
'rules',
|
'rules',
|
||||||
],
|
],
|
||||||
|
boolean: [
|
||||||
|
'count',
|
||||||
|
],
|
||||||
count: ['v'],
|
count: ['v'],
|
||||||
default: {
|
default: {
|
||||||
[CONFIG_ARGS_NAME]: `.${VERSION_INFO.app.name}.yml`,
|
[CONFIG_ARGS_NAME]: `.${VERSION_INFO.app.name}.yml`,
|
||||||
[CONFIG_ARGS_PATH]: [],
|
[CONFIG_ARGS_PATH]: [],
|
||||||
|
'count': false,
|
||||||
'excludeLevel': [],
|
'excludeLevel': [],
|
||||||
'excludeName': [],
|
'excludeName': [],
|
||||||
'excludeTag': [],
|
'excludeTag': [],
|
||||||
|
@ -69,24 +74,33 @@ export async function main(argv: Array<string>): Promise<number> {
|
||||||
const activeRules = await resolveRules(rules, args.argv as any);
|
const activeRules = await resolveRules(rules, args.argv as any);
|
||||||
|
|
||||||
// run rules
|
// run rules
|
||||||
let status = STATUS_SUCCESS;
|
let errors = 0;
|
||||||
switch (args.argv.mode) {
|
switch (args.argv.mode) {
|
||||||
case 'check':
|
case 'check':
|
||||||
for (const rule of activeRules) {
|
for (const rule of activeRules) {
|
||||||
if (checkRule(rule, data)) {
|
if (checkRule(rule, data, logger)) {
|
||||||
logger.info({ rule }, 'passed rule');
|
logger.info({ rule }, 'passed rule');
|
||||||
} else {
|
} else {
|
||||||
logger.warn({ rule }, 'failed rule');
|
logger.warn({ rule }, 'failed rule');
|
||||||
status = STATUS_ERROR;
|
++errors;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logger.error({ mode: args.argv.mode }, 'unsupported mode');
|
logger.error({ mode: args.argv.mode }, 'unsupported mode');
|
||||||
status = STATUS_ERROR;
|
++errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
if (errors > 0) {
|
||||||
|
logger.error({ errors }, 'some rules failed');
|
||||||
|
if (args.argv.count) {
|
||||||
|
return errors;
|
||||||
|
} else {
|
||||||
|
return STATUS_ERROR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main(process.argv).then((status) => process.exit(status)).catch((err) => {
|
main(process.argv).then((status) => process.exit(status)).catch((err) => {
|
||||||
|
|
15
src/rule.ts
15
src/rule.ts
|
@ -2,7 +2,7 @@ import * as Ajv from 'ajv';
|
||||||
import { readFile } from 'fs';
|
import { readFile } from 'fs';
|
||||||
import { JSONPath } from 'jsonpath-plus';
|
import { JSONPath } from 'jsonpath-plus';
|
||||||
import { intersection } from 'lodash';
|
import { intersection } from 'lodash';
|
||||||
import { LogLevel } from 'noicejs';
|
import { LogLevel, Logger } from 'noicejs';
|
||||||
import { promisify } from 'util';
|
import { promisify } from 'util';
|
||||||
import { safeLoad } from 'js-yaml';
|
import { safeLoad } from 'js-yaml';
|
||||||
import { CONFIG_SCHEMA } from './config';
|
import { CONFIG_SCHEMA } from './config';
|
||||||
|
@ -81,12 +81,21 @@ export async function resolveRules(rules: Array<Rule>, selector: RuleSelector):
|
||||||
return Array.from(activeRules);
|
return Array.from(activeRules);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkRule(rule: Rule, data: any): boolean {
|
export function checkRule(rule: Rule, data: any, logger: Logger): boolean {
|
||||||
const ajv = new ((Ajv as any).default)()
|
const ajv = new ((Ajv as any).default)()
|
||||||
const schema = ajv.compile(rule.schema);
|
const schema = ajv.compile(rule.schema);
|
||||||
const scopes = JSONPath({
|
const scopes = JSONPath({
|
||||||
json: data,
|
json: data,
|
||||||
path: rule.nodes.select,
|
path: rule.nodes.select,
|
||||||
});
|
});
|
||||||
return scopes.every((s: any) => schema(s));
|
|
||||||
|
for (const scope of scopes) {
|
||||||
|
const valid = schema(scope);
|
||||||
|
if (!valid) {
|
||||||
|
logger.warn({ errors: schema.errors, item: scope }, 'rule failed on item');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
Loading…
Reference in New Issue