feat: Check request body fields against OpenAPI - #4576
Conversation
Signed-off-by: Glenn Lewis <6598971+gmlewis@users.noreply.github.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #4576 +/- ##
=======================================
Coverage 98.59% 98.59%
=======================================
Files 197 197
Lines 18326 18326
=======================================
Hits 18068 18068
Misses 258 258 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Signed-off-by: Glenn Lewis <6598971+gmlewis@users.noreply.github.com>
There was a problem hiding this comment.
Can we use .yml/.yaml file instead of .txt
There was a problem hiding this comment.
The file is a flat one-key-per-line list plus a comment header that the tool preserves verbatim when it rewrites the file. YAML buys nothing here but costs a parser dependency (the module currently requires only go-cmp) and comment round-tripping (yaml.v3 drops comments, so -fix/-write-exceptions would lose the header). If the format ever needs per-entry metadata, we can change it. But for now, txt is the better choice, IMO.
Signed-off-by: Glenn Lewis <6598971+gmlewis@users.noreply.github.com>
|
@Not-Dhananjay-Mishra - thank you for the review! I addressed two of your comments, and pushed back on the other two 😄. PTAL. |
| case f.isStruct: | ||
| // CONTRIBUTING.md prefers omitzero over a pointer for structs, and it is the | ||
| // only omit option that works on a struct value. | ||
| c.add(&diagnostic{ | ||
| sev: sevWarn, rule: ruleOptionalValueType, file: f.file, line: f.line, | ||
| owner: si.name, field: f.goName, info: f, action: &fixAction{addOmit: "omitzero"}, | ||
| message: fmt.Sprintf("%q is optional in the schema, but the Go field is a value type, so it is always sent: add omitzero", f.jsonName), | ||
| }) |
There was a problem hiding this comment.
I think our structfield linter will not allow this kind of case, where a non-pointer struct uses omitzero.
type SomeRequest struct {
OptionalStruct Struct `json:"optional_struct,omitzero"`
}There was a problem hiding this comment.
I think the reason that all tests pass is because our linters are guarded by the "github" package name.
There was a problem hiding this comment.
I think the reason that all tests pass is because our linters are guarded by the "github" package name.
linters are not running inside testdata/... so that why linter didn't caught it.
tools/schemafields/testdata/golden/TestFix/github/runner_groups.go
// StructTypeRequest has an optional property of a struct value type.
type StructTypeRequest struct {
// Inner is optional and CONTRIBUTING.md asks for omitzero on structs.
Inner InnerConfig `json:"inner,omitzero"`
}I moved it outside temporary to test it, and linters start complaning.
tools/schemafields/runner_groups.go:23:2: change the "ResponseOnly" field type to "*string" in the struct "CreateRunnerGroupRequest" because its json tag uses "omitempty" (structfield)
ResponseOnly string `json:"response_only,omitempty"`
^
tools/schemafields/runner_groups.go:47:2: change the "Inner" field type to "*InnerConfig" in the struct "StructTypeRequest" (structfield)
Inner InnerConfig `json:"inner,omitzero"`I believe that we should suggest %q is optional in the schema, but the Go field is a value type, so it is always sent: use pointer with omitempty
There was a problem hiding this comment.
You are absolutely right, @Not-Dhananjay-Mishra!
I believe this is now fixed and I removed the 19 false-positives that were caused by this error.
PTAL.
Signed-off-by: Glenn Lewis <6598971+gmlewis@users.noreply.github.com>
|
|
||
| print_header "Checking request body fields against the OpenAPI schemas" | ||
| if script/check-schema-fields.sh; then | ||
| printf "${GREEN}✔ request body fields match the OpenAPI schemas${NC}\n" | ||
| else | ||
| printf "${RED}✘ request body fields disagree with the OpenAPI schemas${NC}\n" | ||
| fail | ||
| fi |
There was a problem hiding this comment.
When running script/lint.sh locally, this doesn't get triggered because it requires the CHECK_GITHUB_OPENAPI=1 environment variable. Is this intentional?
There was a problem hiding this comment.
Good call! I've removed it.
| The `tools/schemafields` package checks Go request body struct field | ||
| optionality against GitHub's OpenAPI request body schemas. It is run by | ||
| `script/check-schema-fields.sh`, which `script/lint.sh` and the `linter` | ||
| workflow call, so you rarely need to run it directly. |
There was a problem hiding this comment.
I feel that this statement
It is run by
script/check-schema-fields.sh, whichscript/lint.shand thelinter
workflow call, so you rarely need to run it directly.
feels inconsistent since contributors need to set the environment variable first then only they can run script/check-schema-fields.sh via script/lint.sh.
Not-Dhananjay-Mishra
left a comment
There was a problem hiding this comment.
Just one small doubt. Otherwise, LGTM 🫠
Signed-off-by: Glenn Lewis <6598971+gmlewis@users.noreply.github.com>
|
Updated. Thank you, @Not-Dhananjay-Mishra! |
Checking new PRs against the official GitHub v3 API for required fields in body parameters is extremely time-consuming, monotonous, and error-prone. This new tool helps contributors and maintainers alike by automating the mechanically-verifiable parts.
This PR adds
tools/schemafields, run byscript/check-schema-fields.shand wired intoscript/lint.shand thelinterworkflow. It checks each request body struct field against the request body schema of the operations that send it, mapping structs to operations via the//meta:operationannotation and the by-valuebodyparameter thatparamcheckrequires, so new endpoints are covered with no new annotation.No breaking API changes are made in this PR, but an upcoming PR will
-fixthe problems found.AI assistance was used to write this PR.
Supersedes #4375 (closed), which required a
//meta:schemaannotation on every struct.Relates to #3644 and #4023, and to the
required-but-omittablebugs in #3336, #3226 and #2909.cc: @stevehipwell - @Not-Dhananjay-Mishra