-
-
Notifications
You must be signed in to change notification settings - Fork 240
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: teach rulesets to accept exceptions #939
Conversation
cff8072
to
5288ca0
Compare
src/rulesets/reader.ts
Outdated
@@ -97,6 +101,7 @@ const createRulesetProcessor = ( | |||
if (extendedRuleset !== null) { | |||
mergeRules(rules, extendedRuleset.rules, parentSeverity); | |||
Object.assign(functions, extendedRuleset.functions); | |||
mergeExceptions(baseUri, exceptions, extendedRuleset.exceptions); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Food for thoughts, but I'm pretty sure we'll want to filter out certain exceptions.
For instance,
{
"file/#": ["foo-rule"],
"file/#.bar": ["foo-rule"]
}
This could be expressed in a single exception "file/#": ["foo-rule"]
.
We'll have fewer paths to query later if we narrow them down here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@P0lip Is that a use case so common that it should be included in that PR or should we wait until we get some feedback that maintaining exceptions is too tedious?
I like this a lot. I guess it would make #923 obsolete. |
78b6c8f
to
07e3314
Compare
64fa0df
to
a748cbb
Compare
@philsturgeon @P0lip Here's a first alpha version of the PR. repro/one.yaml
repro/ruleset.yaml
cli usage
I'm going to start working on the doco. /cc @m-mohr Would you agree to give it a try against your own use cases, I'd be delighted to get some feedback! |
src/runner.ts
Outdated
): IRuleResult[] => { | ||
const results: IRuleResult[] = []; | ||
|
||
// TODO: | ||
// Ruleset | ||
// - To be investigated: How to cope with STDIN as a source and exception relative locations? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@P0lip I haven't started to dig into that. Any idea?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@P0lip As I'm not sure how to build a ruleset that would be able to reference a document passed through STDIN, I'm wondering if issuing a warning wouldn't be the best short-term approach.
When the ruleset contains exceptions
And the document is passed as STDIN
A warning would be issued notifying that exceptions handling isn't supported in that mode and that the run will ignore them.
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you STDIN a file, it may well still have $ref's, and those $ref's would still have exceptions working just the same right? It'd just be the initial "entry file" being passed in as STDIN, and that could have things ignored with {ENTRY FILE OR ROOT IDENTIFIER}#/components
and not mentioning a filename? Or do we need some sort of wildcard for saying "this is the first/main/root/entry file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@philsturgeon I'm not even sure how a $ref containing a relative file location would be resolved in that context and I can't find any test in the codebase about that use case. Does it consider the current working directory as the root to be used?
@P0lip Any idea?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC, the document path would be equal to the output of process.cwd()
.
I wouldn't really bother too much though, as it's kind of expected you provide a dereferenced document as STDIN.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah CWD.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉 It took me some time (as Windows and tty don't play well together) but I managed to find a way to honor exceptions in a stdin
context.
@P0lip @philsturgeon Could you please take a look at the proposal?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a side note, that more or less compelled me to find a sustainable way to develop in a xplat way from a Windows computer. I'm going to open a series of tiny pull requests to make contributing from Windows a bit easier.
bb6fc90
to
ea310bd
Compare
ea310bd
to
990224d
Compare
990224d
to
1b0752f
Compare
I like this approach, but what do you think of also supporting something in the OpenAPI itself, e.g. something like this: openapi: 3.0.0
info:
version: 1.0.0
title: Stoplight
x-linter-ignore:
- info-contact
x-linter-ignore:
- oas3-api-servers
paths: {} Then the exceptions can be explicitly listed in the API description document rather than having to link two places via paths in separate documents, and it prevents the need for an almost empty You'd have to decide if the rules apply to all children as well, e.g. if ignoring a camel-casing rule on a path would apply to all parameters for all operations under that path. |
ca194cd
to
b0b778b
Compare
@danielgtaylor I'd like to keep the scope of this PR to ruleset based ignore, but we could have another issue discussing the pros and cons of letting API description authors mark their own descriptions with ignores. It could be seen as a bit cheeky, trying to squeak an API with "naughty things" past automated API governance, but... make a case for it in a new issue and we'll see! :D |
052eec4
to
4fc6f28
Compare
@@ -249,6 +249,51 @@ The example above will run all of the rules defined in the `spectral:oas` rulese | |||
|
|||
- [Rules relevant to OpenAPI v2 and v3](../reference/openapi-rules.md) | |||
|
|||
## Selectively silencing some results | |||
|
|||
From time to time, you want to ignore some specific results without turning off |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please can we try to pick a word and stick to it? Using both "silencing" and "ignoring" is ok, but then we talk about exceptions.
Can we either ignore
, or except
? I think personally think ignore
is more clear, and in line with .eslintignore
, .gitignore
, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@philsturgeon Fixed. Do you like it better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this is great! I'll give it a lick of paint after so you can focus on writing amazing code instead of mucking around with minor tweaks.
docs/getting-started/rulesets.md
Outdated
|
||
`except` describes a map of locations (expressed as Json paths) and rules that should be ignored. | ||
|
||
Locations be can either described as relatively to the ruleset or absolute paths. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Locations be can either described as relatively to the ruleset or absolute paths. | |
Locations be can either described as relative to the ruleset or absolute paths. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@philsturgeon Fixed
d4bb66a
to
08a1959
Compare
docs/getting-started/rulesets.md
Outdated
extends: spectral:oas | ||
|
||
except: | ||
"<STDIN>#": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to mess around with this. I think putting something in the ruleset which demands knowledge of exactly how it's being called is going to be more confusion than its worth.
I would expect to see people writing #/info
, or models/awful.json
to make it shut up about issues in info, or a particularly awful model. If that info ignore just so happens to quieten up two different infos im not sure people will be that upset.
Let's try and avoid overthinking things, and leave room for more improvements later if we get feedback that they're required. I don't think entrance files are the biggest concern for people, and if they are a more specific exception can be written, so this will possibly not come up for a long time - if ever. 🎲
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@philsturgeon Thanks for the detailed feedback!
The current implementation was designed to help make one of the initial requirements happen (from #747 (comment))
As such, the current syntax expects a file and a non ambiguous path within it that should be ignored.
Of course, the model can be extended to support more "handwritten" scenarios:
models/awful.json: [ rule1, rule2]
: Would ignore rule1 and rule2 results wheverever in the file#/info": [rule1, rule2]
: Would ignore rule1 and rule2 results in any processed document provided they originate from a path that's#/info
or below (eg.#/info/sub/path/1
). This would be in line with @P0lip's comment
Would that fit you better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok if that’s the goal just ignore STDIN entirely and support files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@philsturgeon Dropped. STDIN and laxer syntax will be tracked through separate issues to keep that PR on scope.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one extra note on STDIN, but looking really good besides that.
src/rulesets/mergers/exceptions.ts
Outdated
set.add(r); | ||
}); | ||
|
||
target[normalizedLocation] = [...set].sort(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
target[normalizedLocation] = [...set].sort(); | |
target[normalizedLocation] = [...set].sort((a, b) => a.localeCompare(b)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@P0lip Fixed
src/rulesets/mergers/exceptions.ts
Outdated
const buildErrorMessagePrefix = ($ref: string, rulesetUri?: string): string => { | ||
let prefix = ''; | ||
|
||
if (rulesetUri !== undefined) prefix += `in ruleset \`${rulesetUri}\`, `; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (rulesetUri !== undefined) prefix += `in ruleset \`${rulesetUri}\`, `; | |
if (rulesetUri !== void 0) prefix += `in ruleset \`${rulesetUri}\`, `; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@P0lip Fixed
docs/getting-started/rulesets.md
Outdated
except: | ||
"<STDIN>#": | ||
- oas3-api-servers | ||
"<STDIN>#/info": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, not a fan of it tbh.
How about ./#info
? This would be more universal IMHO, as you could also target the input document, i.e. it'd target foo.yaml
in when the following command spectral lint foo.yaml
is executed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been recommending we just ditch STDIN support entirely it's not worth the hassle generally speaking we should plan features before we get people working on them :D
This is trying to solve the Studio use case, and if people ask for this we can bring it in, but until then its scope creep.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@P0lip @philsturgeon STDIN support has been dropped. A warning is now generated when the document is consumed from stdin and the ruleset contains exceptions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is trying to solve the Studio use case, and if people ask for this we can bring it in, but until then its scope creep.
Studio should not be affected too much, since it doesn't use STDIN.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@P0lip that's what im trying to say. We are trying to get this working for the studio use case, which doesnt need STDIN, so we don't need to worry about STDIN here.
aa2e102
to
a3d4f9b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good to me.
src/document.ts
Outdated
@@ -6,6 +6,8 @@ import { IParser } from './parsers/types'; | |||
import { IRuleResult } from './types'; | |||
import { startsWithProtocol } from './utils'; | |||
|
|||
export const StdIn: string = '<STDIN>'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
export const StdIn: string = '<STDIN>'; | |
export const STDIN: string = '<STDIN>'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@P0lip Fixed
a3d4f9b
to
0148062
Compare
Fixes #747.
Checklist
except
to cope with STDIN input #1001)Does this PR introduce a breaking change?