Add .NET bindings - #475
Conversation
Adds a `protoc_builtin: csharp` entry to buf.gen.yaml alongside java and kotlin, the generated `bindings/dotnet/src/Scip.cs`, and a project that packs to the `Scip` NuGet package. protoc's C# backend emits an uncompilable `Descriptor` class (CS0542), so proto-generate renames the generated class to `SymbolDescriptor`. The Protobuf message itself is untouched.
Builds and packs bindings/dotnet with `buildDotnetModule`, pinned to the .NET 10 SDK, and asserts the project version matches cmd/scip/version.txt in the same style as the Rust, Haskell and TypeScript checks.
The PR check builds bindings/dotnet with a stock SDK and validates the package version against cmd/scip/version.txt, as the JVM bindings check does. The release workflow packs and pushes the Scip package to NuGet through `nix develop`, like the crate and Hackage jobs.
Adds bindings/dotnet/Scip.csproj to the list of files a version bump touches, and a NuGet publishing section alongside the JVM one.
`Scip.Index` is ambiguous with `System.Index` under implicit usings, so the README example aliases it. Google.Protobuf joins protobuf-java in the renovate rule that keeps the runtime in lock-step with flake.nix's protoc.
|
One practical note on the
The risk is low - SCIP has existed four years and nobody has taken it - but it is not zero, and this could sit for a while. Happy to do whichever suits you:
Default assumption is the first. Nothing here blocks review of the code. |
jupblb
left a comment
There was a problem hiding this comment.
Overall this looks good to me but we need to switch to Trusted Publishing. I don't want to update the API key every month (current NuGet limitation).
Please make the appropriate changes and I'll proceed with the setup on NuGet. Alternatively, I can invite you to the https://www.nuget.org/profiles/scip-code org and you can do this yourself. Take your pick.
Thank you for taking care of this, much appreciated! :)
|
|
||
| on: | ||
| pull_request: | ||
| paths: |
There was a problem hiding this comment.
I'm ok with this running on every PR. I prefer we didn't have to maintain this list of paths.
| # the descriptor pool still says `scip.Descriptor` - to | ||
| # SymbolDescriptor, the name used both by scip.proto's own | ||
| # comments and by the existing scip-dotnet bindings. | ||
| sed -i -E \ |
There was a problem hiding this comment.
This is awful and if it can't be done better with nix it's fine to leave as is. But I'll appreciate a lot if this can be replaced with something more sound and future-proof.
Drops the `paths` filter so there is no list to keep in sync as the project grows.
Replaces the `NUGET_API_KEY` secret with an OIDC exchange: the job requests a GitHub id-token and `NuGet/login` trades it for an API key that expires after an hour, so there is no long-lived key to rotate (nuget.org now caps manually created keys at 30 days). Needs a trust policy on nuget.org naming scip-code/scip and release.yaml, plus a `NUGET_USER` secret holding the nuget.org profile name that owns the policy. Both are written up in docs/Development.md.
The eight expressions stay, because the alternatives are worse: renaming the message in a copy of scip.proto (what sourcegraph/scip-dotnet does) drops `scip.Descriptor` from the descriptor pool, `Any` type URLs and canonical JSON, and protoc's C# backend has no option to rename a class without renaming the message. What was missing was anything that fails when protoc's output moves, so add two checks to proto-generate: - scip.proto must still declare a message named Descriptor, so a rename there cannot silently reduce this step to a no-op; - folding SymbolDescriptor back to Descriptor must reproduce protoc's output, which proves the expressions are a rename and nothing else. Over-renaming now fails in proto-generate, under-renaming already failed in the dotnet-bindings check because the file stops compiling. Both are verified: an extra expression, and a renamed message, each abort the run.
|
All three addressed in 7b77cb5, bbe913d, 2622995. Trusted publishing - Invite, please - happy to do the NuGet side myself, so an invite to the
The sed - kept, but guarded. Renaming the message in a proto copy would change the descriptor pool, |
jupblb
left a comment
There was a problem hiding this comment.
LGTM! What's your NuGet username?
| # the descriptor pool still says `scip.Descriptor` - to | ||
| # SymbolDescriptor, the name used both by scip.proto's own | ||
| # comments and by the existing scip-dotnet bindings. | ||
| sed -i -E \ |
Adds .NET bindings, as discussed in #468.
bindings/had go, haskell, java, kotlin, rust and typescript, so anyone writing a .NET SCIP producer or consumer vendorsscip.protoby hand today. Sourcegraph's ownscip-dotnetdoes, and so does the tool this came out of.The three things asked for
The bindings. Package id
Scip, targetingnetstandard2.0. Generated by a newprotoc_builtin: csharpentry inbuf.gen.yaml, alongside the existingjavaandkotlinones. The generated file is committed and markedlinguist-generated, matching what the other bindings do; CI regenerates and runsgit diff --exit-code, so it cannot drift.netstandard2.0because the bindings are pure generated data types with no framework-specific surface, so it costs nothing and reaches .NET Framework 4.6.1 and above, Mono and Unity, and every modern .NET.Google.Protobufships anetstandard2.0assembly.Nix. A
dotnet-bindingscheck inchecks.nixin the same shape asgo-bindings, plus what the devShell needs.The
formattingcheck still passes with these files in place.Release automation. A
publish-dotnet-bindingsjob inrelease.yamlin the shape of the existing per-binding publish jobs, plus adotnet-bindings.yamlPR check modelled onjvm-bindings.yaml, including its validation that the version matchescmd/scip/version.txt.One wrinkle worth knowing about
protoc's C# backend emits a
Descriptorclass that does not compile: CS0542, because every generated protobuf type already carries a staticDescriptorproperty. Soproto-generaterenames the class toSymbolDescriptor.The message itself is untouched, and
SymbolDescriptor.Descriptor.FullNamestill returnsscip.Descriptor, so nothing about the wire format or the schema changes. It is also whatsourcegraph/scip-dotnetalready ships, so anyone moving between the two sees the same name.Verified against a real index
Rather than only checking it compiles, a console app consuming the packed
Scip.0.9.0.nupkgread a realscip-typescript0.4.0 index of 60,867 bytes:Re-encoding produces a byte-identical 60,867 bytes, and the reparsed index
.Equals(original).Needs something at your end
A
NUGET_API_KEYActions secret, scoped to "Push new packages and package versions". TheScipid is unregistered, so the first release creates it - worth claiming from an org account rather than a personal one if you have a preference.Nothing else: no nix, runner or branch-protection changes.
One maintenance note for whoever does the next release:
bindings/dotnet/deps.jsonmust be regenerated wheneverGoogle.Protobufmoves, in lock-step with flake.nix's protoc. The command is documented inchecks.nix, and renovate is pinned off that dependency so it cannot bump it silently.