Skip to content

Promote the generation preview to Goa v3.31.0 - #3971

Merged
raphael merged 121 commits into
v3from
fix/goa-generation-plan
Sep 16, 2026
Merged

raphael merged 121 commits into
v3from
fix/goa-generation-plan

Conversation

@raphael

@raphael raphael commented Aug 24, 2026

Copy link
Copy Markdown
Member

Goa v3.31.0 promotes the generation preview to stable. The generator now records the complete design, generated packages, declarations, imports, conversions, and validators before writing files. Every service, transport, command, example, OpenAPI document, and plugin uses those same choices. This fixes disagreements between independently generated declarations and callers that previously produced invalid or inconsistent code.

This is a substantial upgrade with intentional breaking changes, while retaining the goa.design/goa/v3 module path. Keeping v3 does not imply source or wire compatibility with every v3.30.0 application. UPGRADING.md is the application migration guide; codegen/ARCHITECTURE.md describes ownership and the complete generator API migration.

Generated behavior

  • One authored declaration has one package owner and one final name. Templates cannot allocate new names or rebuild transport analysis. Shared types, imports, unions, error methods, examples, and plugin declarations use that ownership across the complete generation run.
  • OneOf stores one selected branch behind generated constructors, setters, accessors, and Kind. Public branch fields are removed. Required unions reject absent or nil selections; selecting a new branch replaces the old one.
  • Required singular protobuf fields preserve presence. An explicit false, 0, or empty value remains explicit, while an omitted required value is rejected before conversion. Scalar protobuf Go fields become pointers; service fields retain their existing layouts. Defaults apply only to absent inputs, never to service results. Repeated and map fields accept valid empty collections because protobuf cannot represent their presence.
  • HTTP and gRPC clients validate and convert the selected result view. A view that intentionally omits a complete-result field no longer produces a false validation failure or a WebSocket client panic. Dynamic gRPC streams convey the chosen view before the first message.
  • JSON-RPC has unary HTTP calls and explicit server-sent-event streams. It validates request IDs and method kinds, notifications, batches, errors, media types, and stream completion. Designed errors use data: {name, body}; caller-selected views use result: {view, body}. Unknown errors retain their raw JSON-RPC representation. JSON-RPC WebSocket, client-streaming, and bidirectional APIs are removed.
  • Incoming ArrayOfRequired JSON arrays reject null primitive items. Multipart decoding validates the body before constructing the service payload. Whole-query maps decode the same raw keys that clients send. HTTP response selection requires exactly one untagged default response. Custom path types retain their imports in generated client and server path files.
  • API-level errors are reusable definitions selected by services or methods. Only the exact declared error type receives error methods. Named string credentials retain their authored types. Interceptor information becomes a read-only interface with the same accessors.
  • Generated commands execute calls, print results, consume supported streams, and return failures. Complete-message gRPC flags use protobuf JSON. Example values remain stable across generation order. OpenAPI schemas, security, and examples match the generated transport contracts.
  • A canceled gRPC call exposes one context cause while preserving the gRPC status and transport details; independent cleanup errors remain visible.

The generation run owns package declarations and imports. Each transport owns its wire schema, presence rules, codecs, and validators. Plugins that add declarations must plan them before names become final. Released registration functions and generator entry points remain, but custom plugins that called removed internal-analysis helpers or constructed changed planning records must migrate.

Upgrade and deployment

  1. Install the Goa module and command at v3.31.0, regenerate the complete gen tree, and compile and test the application. Never mix generated versions. Goa requires Go 1.25; the examples and plugins repositories retain their existing Go 1.26 requirement.
  2. For gRPC, install protoc-gen-go v1.36.12 and protoc-gen-go-grpc v1.6.2, then regenerate protobuf code. Update direct scalar message literals for pointers. Update clients before enabling new server presence validation when required zero or empty values matter.
  3. Update handwritten union, interceptor, multipart, direct transport-helper, and command-starter callers. goa example preserves existing handwritten files and cannot migrate those callers automatically.
  4. Regenerate and coordinate both peers for designed JSON-RPC errors, caller-selected JSON-RPC views, JSON-RPC server-sent-event streams, affected viewed gRPC methods and streams, optional primitive HTTP SSE data, and changed gRPC metadata text. Mixed versions cannot be assumed to interoperate in these cases. Use a coordinated cutover or route to matching server versions.
  5. Upgrade the official plugins to the coordinated v3.31.0 release. Custom declaration-producing plugins must use the planning lifecycle described in the architecture guide.

There is no persisted-data migration. Rollback restores the previous design, handwritten callers, dependency versions, and complete generated tree or matching binaries. Roll back both peers together for changed transport exchanges.

Release review and validation

  • Full checks pass on Go 1.25.14: lint, all Goa tests, generated-package compilation and runtime tests, and JSON-RPC integration tests. Generated test modules pin Clue v1.2.6 so a new Clue release cannot raise the tested toolchain minimum. Applications keeping Go 1.25 can use the same Clue version; Clue v1.3.0 requires Go 1.26.
  • The new custom-path test generates and compiles complete HTTP client and server packages using uuid.UUID.
  • The stable branch's gRPC dependency, cancellation, and protobuf collection fixes are included.
  • The release script verifies the expected stable branches without switching worktrees, pulls only by fast-forward, enforces major version 3, and updates all four plugins modules. Its version guards and dry run were checked.
  • Open issues were reviewed across Goa, examples, and plugins. Small reproductions for JWT cookies, SSE request IDs, and the reported YAML string example generate and compile. The custom UUID query encoder and recursive gRPC result-array failures also reproduce on v3.30.0; they are documented existing limitations, not claimed fixes.

The synchronized downstream branches are reviewed in goadesign/examples#219 and goadesign/plugins#271. All 19 example modules and all four plugins modules pass local generation/build/test checks against this generator; all downstream CI checks pass and both PRs are merged. Goa CI also passes on Go 1.25 Linux and Windows, alongside dependency review and CodeQL. This PR merges the implementation and migration guide; the release workflow creates the final version commit and tags afterward.

Review codegen/generation.go, codegen/generator/plan.go, and the service/transport plans for ownership; the union and validation code for value semantics; grpc/codegen/protobuf_catalog.go and conversion planning for presence and views; and jsonrpc/types.go plus the JSON-RPC generators for the changed exchanges. The architecture guide maps each removed or changed exported generator API to its replacement.

raphael added 30 commits August 20, 2026 21:19
@raphael raphael changed the title Generate one exact contract across every Goa output Promote the generation preview to Goa v3.31.0 Sep 16, 2026
@raphael
raphael marked this pull request as ready for review September 16, 2026 07:18
@raphael
raphael merged commit ae4257e into v3 Sep 16, 2026
5 checks passed
@raphael
raphael deleted the fix/goa-generation-plan branch September 16, 2026 07:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants