fix(visitor): include rule name and selector in error messages
This commit is contained in:
parent
5fefe0c79d
commit
fcd4740eee
26
README.md
26
README.md
|
@ -197,8 +197,30 @@ the easiest to read, and can be pretty-printed by redirecting `stderr` through `
|
|||
}
|
||||
```
|
||||
|
||||
Using `jq` allows for additional filtering, for example `>(jq 'select(.level > 30)')` will only print warnings and
|
||||
errors (log level is also part of the configuration file).
|
||||
Using `jq` allows for additional filtering and formatting. For example, `>(jq 'select(.level > 30)')` will only print
|
||||
warnings and errors (log level is also part of the configuration file).
|
||||
|
||||
To print the last line's message and error messages: `>(tail -1 | jq '[.msg, ((.errors // [])[] | .msg)]')`
|
||||
|
||||
```shell
|
||||
> cat test/examples/kubernetes-resources-high.yml | salty-dog \
|
||||
--rules rules/kubernetes.yml \
|
||||
--tag kubernetes 2> >(tail -1 | jq '[.msg, ((.errors // [])[] | .msg)]')
|
||||
|
||||
[
|
||||
"all rules passed"
|
||||
]
|
||||
|
||||
> cat test/examples/kubernetes-resources-some.yml | salty-dog \
|
||||
--rules rules/kubernetes.yml \
|
||||
--tag kubernetes 2> >(tail -1 | jq '[.msg, ((.errors // [])[] | .msg)]')
|
||||
|
||||
[
|
||||
"some rules failed",
|
||||
".resources.limits should have required property 'memory' at $.spec.template.spec.containers[*] for kubernetes-resources",
|
||||
".metadata should have required property 'labels' at $ for kubernetes-labels"
|
||||
]
|
||||
```
|
||||
|
||||
### Modes
|
||||
|
||||
|
|
|
@ -156,7 +156,7 @@ export async function parseArgs(argv: Array<string>): Promise<ParseResults> {
|
|||
.version(VERSION_INFO.package.version)
|
||||
.alias('version', 'v');
|
||||
|
||||
// @TODO: this should not need a cast but the parser's type only has the last option (include-tag)
|
||||
// @TODO: this should not need a cast but the parser's type omits command options and doesn't expose camelCase
|
||||
// tslint:disable-next-line:no-any
|
||||
const args = parser.argv as any;
|
||||
return {
|
||||
|
|
|
@ -57,7 +57,7 @@ export class SchemaRule implements RuleData, Visitor {
|
|||
if (filter(node)) {
|
||||
ctx.logger.debug({ item: node }, 'checking item');
|
||||
if (!check(node) && hasItems(check.errors)) {
|
||||
errors.push(...check.errors.map(friendlyError));
|
||||
errors.push(...check.errors.map((err) => friendlyError(ctx, err, this)));
|
||||
}
|
||||
} else {
|
||||
ctx.logger.debug({ errors: filter.errors, item: node }, 'skipping item');
|
||||
|
|
|
@ -1,22 +1,25 @@
|
|||
import { ErrorObject } from 'ajv';
|
||||
import { isNil } from 'lodash';
|
||||
|
||||
import { SchemaRule } from '../../rule/SchemaRule';
|
||||
import { VisitorContext } from '../../visitor/VisitorContext';
|
||||
import { VisitorError } from '../../visitor/VisitorError';
|
||||
|
||||
export function friendlyError(err: ErrorObject): VisitorError {
|
||||
export function friendlyError(ctx: VisitorContext, err: ErrorObject, rule: SchemaRule): VisitorError {
|
||||
return {
|
||||
data: {
|
||||
err,
|
||||
rule,
|
||||
},
|
||||
level: 'error',
|
||||
msg: friendlyErrorMessage(err),
|
||||
msg: friendlyErrorMessage(err, rule),
|
||||
};
|
||||
}
|
||||
|
||||
export function friendlyErrorMessage(err: ErrorObject): string {
|
||||
export function friendlyErrorMessage(err: ErrorObject, rule: SchemaRule): string {
|
||||
if (isNil(err.message)) {
|
||||
return `${err.dataPath} ${err.keyword}`;
|
||||
return `${err.dataPath} ${err.keyword} at ${rule.select} for ${rule.name}`;
|
||||
} else {
|
||||
return `${err.dataPath} ${err.message}`;
|
||||
return `${err.dataPath} ${err.message} at ${rule.select} for ${rule.name}`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,34 @@
|
|||
import { expect } from 'chai';
|
||||
import { NullLogger } from 'noicejs';
|
||||
|
||||
import { SchemaRule } from '../../../src/rule/SchemaRule';
|
||||
import { friendlyError } from '../../../src/utils/ajv';
|
||||
import { VisitorContext } from '../../../src/visitor/VisitorContext';
|
||||
|
||||
const TEST_NAME = 'test';
|
||||
|
||||
describe('friendly errors', () => {
|
||||
it('should have a message', () => {
|
||||
const err = friendlyError({
|
||||
const err = friendlyError(new VisitorContext({
|
||||
innerOptions: {
|
||||
coerce: false,
|
||||
defaults: false,
|
||||
mutate: false,
|
||||
},
|
||||
logger: NullLogger.global,
|
||||
}), {
|
||||
dataPath: 'test-path',
|
||||
keyword: 'test',
|
||||
keyword: TEST_NAME,
|
||||
params: { /* ? */ },
|
||||
schemaPath: 'test-path',
|
||||
});
|
||||
}, new SchemaRule({
|
||||
check: {},
|
||||
desc: TEST_NAME,
|
||||
level: 'info',
|
||||
name: TEST_NAME,
|
||||
select: '',
|
||||
tags: [TEST_NAME],
|
||||
}));
|
||||
expect(err.msg).to.not.equal('');
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue