-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Render Azure, JSON, and JSON lines output with the new diagnostics #19133
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
Conversation
|
|
6601b4c
to
200c1a7
Compare
This reverts commit 5d918e9.
200c1a7
to
c3e3077
Compare
I introduced some intentional typos to see if any integration tests fail, and we have one for JSON ( |
Summary -- I spun this off from #19133 to be sure to get an accurate baseline before modifying any of the formats. I picked the code snippet to include a lint diagnostic with a fix, one without a fix, and one syntax error. I'm happy to expand it if there are any other kinds we want to test. Test Plan -- New CLI tests
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.
Nice! Feel free to ignore/disagree with my nits about json!
. :-)
"end_location": location_to_json(end_location.unwrap_or_default()), | ||
"filename": filename.unwrap_or_default(), | ||
"noqa_row": noqa_location.map(|location| location.line) | ||
}) |
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.
Out of curiosity, how come the json!
macro instead of types? I'd imagine json!
to be slower since it has to shove everything into the serde_json::Value
type, but I guess I'd also imagine it probably doesn't matter 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.
I just pulled these over from the current Ruff version, so I'm not too sure. @MichaReiser might know, it looks like there were types deriving Serialize
before #3895.
json!
is kind of handy here for the preview
behavior, but otherwise I'd lean toward types too.
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. Wasn't it already like this before my PR and all I did was splitting the code into different modules.
I'm generally in favor of structs. It makes accidental schema changes easier to spot
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.
Ah yeah sorry, I didn't realize this was copied code. I thought it was newly written.
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.
No worries, I should have pointed it out to help with the review. I opened #19270 to explore using structs.
|
||
s.end() | ||
} | ||
} |
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 feel like if you're using the json!
macro everywhere already, it's probably not worth a hand-impl of the Serialize
trait? There's a bit more ceremony with it compared to just building a Value::Array(Vec<Value>)
directly.
Summary -- I spun this off from #19133 to be sure to get an accurate baseline before modifying any of the formats. I picked the code snippet to include a lint diagnostic with a fix, one without a fix, and one syntax error. I'm happy to expand it if there are any other kinds we want to test. I initially passed `CONTENT` on stdin, but I was a bit surprised to notice that some of our output formats include an absolute path to the file. I switched to a `TempDir` to use the `tempdir_filter`. Test Plan -- New CLI tests
## Summary See #19133 (comment) for recent discussion. This PR moves to using structs for the types in our JSON output format instead of the `json!` macro. I didn't rename any of the `message` references because that should be handled when rebasing #19133 onto this. My plan for handling the `preview` behavior with the new diagnostics is to use a wrapper enum. Something like: ```rust #[derive(Serialize)] #[serde(untagged)] pub(crate) enum JsonDiagnostic<'a> { Old(OldJsonDiagnostic<'a>), } #[derive(Serialize)] pub(crate) struct OldJsonDiagnostic<'a> { // ... } ``` Initially I thought I could use a `&dyn Serialize` for the affected fields, but I see that `Serialize` isn't dyn-compatible in testing this now. ## Test Plan Existing tests. One quirk of the new types is that their fields are in alphabetical order. I guess `json!` sorts the fields alphabetically? The tests were failing before I sorted the struct fields. ## Other formats It looks like the `rdjson`, `sarif`, and `gitlab` formats also use `json!`, so if we decide to merge this, I can do something similar for those before moving them to the new diagnostic format.
the remaining `message` fields are in the actual JSON schema and seem appropriate. they aren't referring to the old internal `Message` implemenation, that's just a reasonable field name for the diagnostic's main message.
} | ||
}; | ||
|
||
json!(value) |
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 feels a bit silly, but callers of this function expect a Display
type. This avoids having to update the callers to use serde_json::to_writer
, which in turn avoids updating their arguments from std::fmt::Formatter
s to something implementing std::io::Write
and their return types to something that can accommodate a serde_json::Error
instead of a std::fmt::Error
.
We could also just call serde_json::to_value
and unwrap it here or in the callers, which is all this macro expands into.
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 would probably move the json!
call to where you need the Display
implementation.
"column": 1, | ||
"row": 5 |
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 actually correct based on testing a released version of Ruff against the real notebook. I think the manual notebook cell index was outdated.
enum JsonDiagnostic<'a> { | ||
Old { | ||
cell: Option<OneIndexed>, | ||
code: Option<&'a SecondaryCode>, | ||
end_location: JsonLocation, | ||
filename: &'a str, | ||
fix: Option<JsonFix<'a>>, | ||
location: JsonLocation, | ||
message: &'a str, | ||
noqa_row: Option<OneIndexed>, | ||
url: Option<String>, | ||
}, | ||
New { | ||
cell: Option<OneIndexed>, | ||
code: Option<&'a SecondaryCode>, | ||
end_location: Option<JsonLocation>, | ||
filename: Option<&'a str>, | ||
fix: Option<JsonFix<'a>>, | ||
location: Option<JsonLocation>, | ||
message: &'a str, | ||
noqa_row: Option<OneIndexed>, | ||
url: Option<String>, | ||
}, |
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.
Using an enum
here strikes me a bit weird. I would either use two separate structs or just ignore the old
entirely and ensure that the values are all Some
where the change isn't backwards compatible.
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.
Oh, for some reason just wrapping the unwrap_or_default
calls in Some
didn't occur to me. That makes a lot more sense. Thanks!
I'm going to merge this and start working on more output formats, happy to follow up if I missed anything. Thanks for the reviews! |
## Summary Another output format like #19133. This is the [reviewdog](https://github.com/reviewdog/reviewdog) output format, which is somewhat similar to regular JSON. Like #19270, in the first commit I converted from using `json!` to `Serialize` structs, then in the second commit I moved the module to `ruff_db`. The reviewdog [schema](https://github.com/reviewdog/reviewdog/blob/320a8e73a94a09248044314d8ca326a6cd710692/proto/rdf/jsonschema/DiagnosticResult.json) seems a bit more flexible than our JSON schema, so I'm not sure if we need any preview checks here. I'll flag the places I wasn't sure about as review comments. ## Test Plan New tests in `rdjson.rs`, ported from the old `rjdson.rs` module, as well as the new CLI output tests. --------- Co-authored-by: Micha Reiser <micha@reiser.io>
Summary
This was originally stacked on #19129, but some of the changes I made for JSON also impacted the Azure format, so I went ahead and combined them. The main changes here are:
FileResolver
for Ruff'sEmitterContext
FileResolver::notebook_index
andFileResolver::is_notebook
methodsDisplayDiagnostics
(with an "s") type for rendering a group of diagnostics at onceAzure
,Json
, andJsonLines
as newDiagnosticFormat
sI tried a couple of alternatives to the
FileResolver::notebook
methods like passing down theNotebookIndex
separately and trying to reparse aNotebook
from Ruff'sSourceFile
. The latter seemed promising, but theSourceFile
only stores the concatenated plain text of the notebook, not the re-parsable JSON. I guess the current version is just a variation on passing theNotebookIndex
, but at least we can reuse the existingresolver
argument. I think a lot of this can be cleaned up once Ruff has its own actual file resolver.As suggested, I also tried deleting the corresponding
Emitter
files inruff_linter
, but it doesn't look like git was able to follow this as a rename. It did, however, track that the tests were moved, so the snapshots should be easy to review.Test Plan
Existing Ruff tests ported to tests in
ruff_db
. I think some other existing ruff tests also cover parts of this refactor.