Skip to content

Latest commit

 

History

History
90 lines (69 loc) · 4.75 KB

File metadata and controls

90 lines (69 loc) · 4.75 KB

Code generation

One contract, two generator toolchains. Both read proto/, which scripts/sync-protos.sh copies from upstream at the SHA recorded in ocp.lock.

Sync

sync-protos.sh clones ocp-protobuf-api, checks out the requested ref, copies only the contract .proto files (upstream's buf.yaml, buf.lock, and buf.gen.yaml describe how the contract repo builds Go, and are not part of what this SDK ships), and rewrites ocp.lock.

This repo owns the java_package namespace. Upstream ships com.codeinc.gen.*; the Android app has always consumed com.codeinc.opencode.gen.*, via a sed/awk pass at the end of its old fetch-protos.sh. sync-protos.sh does that rewrite instead, so the published artifact needs no consumer-side post-processing, and it fails the sync if any com.codeinc.gen. survives the pass. Swift is unaffected: java_package does not influence swift-protobuf naming.

proto_deps/validate/validate.proto is an include-path dependency and is never generated. The Gradle side gets it from the protovalidate plugin's own JAR; the Swift script passes proto_deps/ on the include path but keeps the file off the generation list. The iOS build used to generate it and then delete the resulting validate_validate.pb.swift — that step is gone.

Kotlin

Generated by the Gradle build, from versions pinned in build.gradle.kts rather than inherited from a consumer, so the artifact is reproducible from that file alone:

Generator Version Output
protoc 4.35.1 java and kotlin builtins, both lite
protoc-gen-grpc-java 1.83.1 grpc stubs, lite
protoc-gen-grpc-kotlin 1.4.1 grpckt stubs, lite
protoc-gen-validate-kt 0.1.1 validate-kt, via the dev.bmcreations.protovalidate plugin in PGV mode

Two things that are easy to trip over:

  • The JVM and Android variants of the protobuf Gradle plugin differ. The JVM variant registers the java builtin by default; the Android variant does not, which is why the app declared java as a plugin and this repo configures the builtin instead.
  • Coroutines are an explicit dependency. The generated grpckt stubs reference kotlinx.coroutines.flow.Flow. The app got that from elsewhere in its graph; a standalone artifact has to declare it, which is why kotlinx-coroutines-core is api here. So is protovalidate-runtime, for the same reason on the validate-kt side.

grpc-kotlin sits at 1.4.1 because that is what the Android app generated with at the cutover. 1.5.0 was tested and differs only in line wrapping — 344 lines, no API change — so the bump is safe, but it belongs in its own commit.

Generated Kotlin is not committed. It is a build input to a published JAR, so the reviewable-diff argument that applies to the Swift below does not apply to it.

Swift

Sources/OCPClientProtocol/ is committed, because SPM ships plain source: for the Swift half, the generated code is the artifact. That makes it possible to change a .proto and forget to regenerate, so CI re-runs scripts/generate-swift.sh and fails if the tree moves.

The generators are pinned in scripts/toolchain.env, and install-swift-toolchain.sh builds the plugins against those pins into .tools/:

PROTOC_VERSION=33.1
SWIFT_PROTOBUF_VERSION=1.33.3
GRPC_SWIFT_PROTOBUF_VERSION=2.1.1
GRPC_SWIFT_VERSION=2.2.0

One of those pins is transitive, and that is the whole reason this file exists. The gRPC stub text is rendered by grpc-swift-2's GRPCCodeGen, which grpc-swift-protobuf pulls in through a floating from: requirement — so the output moves when grpc-swift-2 releases, with the plugin's own version unchanged. 2.2.1 added Sendable to the metadata enums; 2.3.0 added type: to every MethodDescriptor. That was ~840 changed lines across 9 files for no contract change. brew install protoc-gen-grpc-swift reproduced the committed output in August 2026 and does not now.

Bumping any of the four is a real change with a real diff. Do it in its own commit and expect Sources/ to move.

What CI checks

.github/workflows/ci.yml runs on every push and PR — a release should never be the first time codegen runs against a new contract or toolchain version.

  • Kotlin: ./gradlew build (protoc plus compiling the result — if the generated code does not compile, the published JAR is broken) and ./gradlew publishToMavenLocal, which catches a missing POM field or an unbuildable sources jar here rather than on the Central upload, where the failure costs a burnt version number. It also writes per-generator file counts to the job summary.
  • Swift: swift build, then regenerate and git diff --quiet -- Sources. The toolchain cache key is scripts/toolchain.env, so a bump rebuilds the plugins and nothing else does.