Repository navigation
Fail the build when a schema that built on the last release stops building - #949
Merged
Merged
Conversation
Each scenario now lists its SDL files and resolvers and configures the rest of the builder, so a test can read its schema and swap its resolvers. The probe compiles the same directory. The type-extensions scenario repeated a field, a member, a value and a directive in its extensions, which 15.0.0 rejects, so it dropped them and its feature page says what 15.0.0 does.
CompatTest builds every scenario, the scenario with its resolvers behind JDK proxies, and invalid SDL variants of it from the grammar: extensions of another kind, undeclared and misplaced directives, wrong argument values, and repeats. It fails when a case that built on the release in src/test/resources/compat throws now, unless accepted.txt lists it. When the pom's major is above the release's, a case may break only if the release logged a WARN for it. -Dcompat.capture records the results for the pom's version.
An invalid extension can hide the error of a scenario that never built, so such a variant built on 14.2.0 by accident.
directive-drift and scalar-directives teach behavior that still builds, so they drop the applications 15.0.0 rejects and the 15.0.0 capture is retaken for them. directives-invalid, context-misbound and jdk-proxy exist to show input 15.0.0 now rejects, so their pages say they exit 2 and quote the error.
An accepted.txt line is now a literal case name, or a regex only when it starts with re:, and needs a reason that names an issue or release notes. A line that matches no failing case fails, and so does an empty capture, an empty scenario list, or a case that built on the release and isn't generated any more. In major mode a release WARN excuses a break only when it names the case's type and item, or the position of the directive the case applies. Errors keep their full message, so an InvalidSchemaException lists its reasons. The 15.0.0 capture is retaken for the longer error text; its cases, WARNs and built count are unchanged.
A proxy error lists every field it can't call, and the last minor warned once per field.
….txt The probe prints graphql.kickstart.tools.compat.scenarios.* since the move, so the feature pages quote that. A repeated directive's error names the directive and its line, not the type. The rule table says what CompatTest checks: input that built keeps building.
A capture taken at a -SNAPSHOT version records the branch, so the next run passes against its own breaks. Capturing now fails there, and the test fails while a capture exists for a version the pom says isn't released yet. A re: line in accepted.txt may match at most 20 cases, all in one scenario, so re:.* can't accept every break silently. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Why
Agents working in graphql-java-tools keep repeating the same mistakes, and the repo should change so a change that looks right from one file is right for the whole repo. One of them is rejecting invalid input that used to build, without the WARN, issue and TODO step that the compatibility rule asks for. It happened 3 times: a kind-mismatched extension became an error (
c4029496), the build threw for JDK proxied resolvers (8611c516), andscalar Date @specifiedBy(url: 5)started throwing (#894, which shipped). Each looked fine from the file it touched, and no test noticed because nothing remembered what the last release accepted.Checklist
Description
verify-toolsscenarios moved intosrc/test/kotlin/graphql/kickstart/tools/compat/scenariosas data: SDL files, resolvers and aconfigurefor the rest of the builder. The probe compiles the same directory, so there's one copy.CompatTestbuilds every scenario 3 ways: as it is, with its resolvers behind JDK proxies, and with one invalid SDL snippet appended per rule of the grammar it can break (an extension of another kind, an undeclared or misplaced directive, a wrong argument value, a repeated field, member, value or directive). That's 1,422 cases, 604 of which build on 15.0.0.src/test/resources/compat/<version>/throws now. The message lists the cases with their full error and says what to do instead: log a WARN, open an issue for the next major and leave the TODO.accepted.txtas one line: the case exactly as the failure lists it, a tab, and why, naming the issue (#N) or the release notes (15.1.0 release notes). A regex only counts when the line starts withre:, so a pastedasync | kind | ...accepts that one case and not every case its|would match. Are:line may accept at most 20 cases, all in one scenario, sore:.*fails instead of accepting everything. 20 fits one operator on one directive or type, and the widest deliberate break so far (14.3.0 applying directives on extensions) needs at most 15 per line that way. A line without a reference, a bad regex, or a line that matches no failing case fails the test.-Dcompat.capturefails at a-SNAPSHOTversion and says captures come from the release tag. The test fails whilesrc/test/resources/compat/has a capture for a version the pom says isn't released yet (15.0.1/at15.0.1-SNAPSHOT), so making one by hand doesn't work either.cases.tsvfails, and so does a case that built on the release and isn't generated any more (a scenario renamed, removed or edited). That failure gives the commands to capture the release again with the current scenarios, or says to list the case inaccepted.txt.kindcase that's the type. For the other snippet cases it's the type and the item (the member or the directive). A directive WARN may point at the application (line 1, column 19) instead of the type, since that's how 14.x worded them. For a seed or proxy case every name its error quotes has to be in one of the WARNs. So the next major can drop what 15.x warned about, but not something it accepted silently, and not something an unrelated WARN in the same scenario happened to mention.InvalidSchemaExceptionshowsinvalid schema: Invalid argument 'url' for applied directive of name 'specifiedBy'instead ofinvalid schema:. The 15.0.0 capture is retaken for that, with v15.0.0'spom.xmlandsrc/main. Its cases, WARNs and built count didn't change.AGENTS.mdgets the capture step for each release (onemvncommand on the tag) and theaccepted.txtformat. Its rule table row now says whatCompatTestchecks: invalid input that built on the last release keeps building until the next major.graphql.kickstart.tools.compat.scenarios.ItemInput, notscenarios.ItemInput).type-extensions.mdsays a repeated directive's error names the directive and its line, not the type.type-extensionsscenario repeated a field, a member, a value and a directive in its extensions, which 15.0.0 rejects, soprobe.sh run type-extensionsexited 2 while its feature page said 0. I dropped the repeats and updated the page.directive-driftandscalar-directivesteach things that still build (applied versus legacy directive lists, scalar directives), so they drop the applications 15.0.0 rejects.directives-invalid,context-misboundandjdk-proxyonly exist to show input that 15.0.0 now rejects, so their pages say exit 2 and quote the error, and the old WARN results moved to Gotchas.type-extensions-repeated-fieldswas already right.Scope
jdk-proxy-cglibcan't build inside the library's Java module in tests (CGLIB can't subclass a class there), so that scenario isn't protected. The probe still runs it.nested-wrappers-exactandtype-extensions-input-orderhave no feature page entry, same as before this PR.Blast Radius
Nobody using the library notices. Contributors get about 2 s more in
mvn verifyon JDK 17, and a PR that starts rejecting input failsCompatTestwith the list of cases. The capture adds a 420 KBcases.tsvto the test resources, and to the test jar.Verification
mvn -B -ntp clean verifyon JDK 17 at the head: 458 tests, build passes,CompatTest1.6 s.c4029496's throw on this branch fails with 512 cases,{kind=511, seed=1}. With the throw still in,-Dcompat.capturefails withpom.xml is at 15.0.1-SNAPSHOT, so a capture would record this branch instead of a releaseand writes nothing. A15.0.1/capture made by setting the pom to15.0.1for the capture run passes on its own, then once the pom is back at15.0.1-SNAPSHOTthe test fails withsrc/test/resources/compat/15.0.1 can't hold a release.re:.*in 15.0.0'saccepted.txtfails withaccepts 604 cases in 30 scenarios.accepted.txt, with the throw re-added: the pasted lineasync | kind | extend interface Query { compatZ: String }takes it to 511.re:async \| kind \| .*takes it to 498, the 14async | kindcases. A line naming a type the scenario doesn't have fails as matching nothing. A line with no tab, one with no#N, andre:with an unclosed group each fail with their line number.asyncscenario fails with the 15 cases that aren't generated any more. An emptycases.tsvfails, and so does an empty scenario list.optional-results-nested(Unwrap a DataFetcherResult inside an Optional #940) is the only one left, which is the same result the any-WARN rule gives. It passes once 14.5.0'saccepted.txtnames it. Editing two 14.5.0 WARNs to name another type, or a different column, makes exactly those 2 cases fail too.context-and-environment-invalid,sourceless-misbound,unmapped-inputs,bookstore-missing-resolver) and the Gotchas ones on the commits they describe (a4736c9afornested-wrappersandnested-wrappers-suspend,3f022b91foroptional-results,f4800425^forjdk-proxy).1987124aran unchanged on the old commits, with captures of v14.2.0 and v14.3.0 taken with these scenarios.c4029496fails with 239 cases with an emptyaccepted.txt, and with 173,{kind=172, seed=1}, once 14.3.0's undeclared directive break is accepted.8611c516fails with 25,{proxy=24, seed=1}.69e18bbdfails with 53,{argval=53}, includingbookstore | argval | extend scalar Date @specifiedBy(url: 5).d47bac59(master before Apply directives and @specifiedBy to scalars #894) passes.a17693b7and76b67394carry 14.3.0's two deliberate breaks (undeclared directives and wrong argument values on extensions), so they pass only once 14.2.0'saccepted.txtlists them.re:line each across every scenario. With this revision those lines fail (accepts 72 cases in 25 scenariosandaccepts 27 cases in 1 scenarios). Written as 27 lines, one per scenario and operator and split by directive intype-extensions,a17693b7and76b67394pass with this revision's test.probe.sh listshows 40 scenarios from the new directory. I ran all 40. The 38 with a page entry exit with the code their page gives, 29 with 0 and 9 with 2. The 2 without one exit 0.