ci: guard the exported API against accidental breaking changes (v1) - #1304
Merged
Conversation
Backport of #1297 to the 1.x maintenance branch, where the guarantee it enforces matters more than it does on main: v1 is a maintenance line, so every break in it is by definition unintended. The build and the tests do not catch every break. Adding a trailing variadic parameter to an exported function changes that function's type: every ordinary call site still compiles, so nothing goes red, while any caller that held the function as a value stops compiling. That reached a release, and a test written specifically to pin backward compatibility did not catch it either, because a plain call expression is exactly the form a trailing variadic can never break. The check runs apidiff over every module and fails on incompatible changes. Adding to the API is always allowed. A deliberate break can be landed by labelling the pull request breaking-change, which still compares and still prints what changed, so the break stays on the record. The workflow already listed v1 among its trigger branches, but a pull_request workflow runs from the head of the branch under test, so it could never fire on a v1 pull request until it existed here. Both files are byte-identical to the ones on main.
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.
What
Backport of #1297 to the
v1maintenance branch. Adds anapidiffcheck that fails a pull request on incompatible changes to the exported API. Adding to the API is always allowed.Both files are byte-identical to the ones on
main.Why here too
The workflow on
mainalready listsv1among its trigger branches, but apull_requestworkflow runs from the head of the branch under test, so it could never fire on av1pull request until it existed onv1. Without this commit the branch is unguarded.The guarantee also matters more here than on
main:v1is a maintenance line for the 1.x series, so any break in its exported API is by definition unintended.What the check catches
The build and the tests do not catch every break. Adding a trailing variadic parameter to an exported function changes that function's type: every ordinary call site still compiles, so nothing goes red, while any caller that held the function as a value stops compiling. That reached a release on the 2.x line, and a test written specifically to pin backward compatibility did not catch it either, because a plain call expression is exactly the form a trailing variadic can never break.
Details worth reviewing
v1is not reported as having removed whateverv1gained in the meantime.apidiff -mper module. Module mode reads every package in a module in a single load and skipsinternal/on its own.breaking-change. The comparison still runs and still prints what changed, so the break stays on the record; it just stops failing.Testing Plan
Run end to end against this branch rather than a synthetic case:
No incompatible changes., 16s.runner.New: reported as./runner.New: changed from func(Config) (*Runner, error) to func(Config, ...any) (*Runner, error)and exits 1.ALLOW_BREAKING=true: still printed, exits 0.apidiffversion installs from a clean module;x/exprequires go 1.24.0, so the Go 1.25 toolchainv1resolves fromgo.modhandles it.bash -n.Generated with CloudCode, session
ses_00f468febffe7dsyc1CNVAgbg7.