Split native packaging into a package family + Cake Frosting build#3
Conversation
Restructure the .NET binding's packaging so the native engine no longer ships inside the managed package: - LadybugDB - managed-only (no native payload) - LadybugDB.Native.<rid> - one package per platform (win-x64, linux-x64, linux-arm64, osx-x64, osx-arm64), carrying just that RID's native library - LadybugDB.Native - meta-package depending on all per-RID packages Consumers reference LadybugDB plus a native package (the meta for "runs anywhere", or a single RID for a slim app). The managed package has no dependency on the natives, which is what enables the slim, single-RID install. Packaging is driven by a new Cake Frosting build under cake/: one parameterized per-RID template plus a meta nuspec. Natives are staged from a locally-built library when present, otherwise downloaded from the pinned engine release via gh and extracted out of the .so/.dylib symlink chain. VerifyPackages asserts the managed assemblies, every per-RID payload, and the meta's deps. The version is single-sourced from version.txt at the binding root (currently 0.17.0-alpha.1): it tracks the upstream engine version with an -alpha.N dev suffix and is read by BuildContext, nuget-package.props, and both workflows. ci.yml and release.yml now invoke the pipeline (dotnet run -- --target ...) instead of inline shell; release publishes all 7 packages to nuget.org via OIDC trusted publishing.
Node 20 JS actions are being force-upgraded on GitHub runners (June 16, 2026). Bump to current Node 24 majors instead of the FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 escape hatch: checkout v4->v6, setup-dotnet v4->v5, upload-artifact v4->v7, download-artifact v4->v8. NuGet/login@v1 already runs on Node 24 (v1.2.0), so it is unchanged.
|
@adsharma 🙌 When you get a moment, could you also review the TODO section - we have to setup an environment here in the repo settings. |
|
This is the same format used by nodejs: https://www.npmjs.com/search?q=ladybugdb%2Fcore What are the benefits of keeping |
|
Can you leave the environment blank for now? We can add it back when we have a release vs test environment.
Done |
Per review (adsharma): leave the GitHub environment blank for now. The nuget.org trusted-publishing policy is environment-blank and NUGET_USER is a repository secret, so a job-level environment claim would not match. A dedicated environment (with an approval gate) can be added back when we split release vs test. HANDOFF notes synced accordingly.
Docker-based example demonstrating the two ways the .NET binding loads the native engine: bundled via the LadybugDB.Native NuGet package, or from a system install (e.g. a Debian package) with a managed-only app. Includes a consumer app, per-scenario Dockerfiles and entrypoint scripts, a .deb builder, and a run.ps1 orchestrator.
Separate packages gives flexibility. If a native library is already available in the system, the user can choose not to install the native package in the C# application and rely on the system library instead. I added an example covering both scenarios: 3dcbbd5 |
Split native packaging into a package family + Cake Frosting build
Summary
Restructures the LadybugDB .NET binding's packaging so the native engine no longer ships inside the
managed package. Instead it's a package family:
LadybugDB— managed-only (no native payload).LadybugDB.Native.<rid>— one package per platform, carrying just that RID's native library.LadybugDB.Native— meta-package that depends on all per-RID packages.Consumers reference
LadybugDBplus a native package: the meta-package for "runs anywhere", or asingle
LadybugDB.Native.<rid>for a slim, single-platform app. All packaging is driven by a newCake Frosting build project under
cake/.Motivation
The old single package bundled every platform's native library into one
.nupkg, so every consumercarried all of them regardless of target. Splitting the natives into per-RID packages (with a meta
"all platforms" package) lets an app pull only what it needs, while keeping a one-line install for the
common case.
What changed
Package family
LadybugDBis now managed-only: removed theruntimes/** native glob fromnuget/nuget-package.props(it now shipslib/net10.0+lib/netstandard2.0+ README + symbols only).LadybugDB.Native.<rid>carriesruntimes/<rid>/native/* plus an emptylib/netstandard2.0/_._marker (so NuGet adds no compile reference) and declares no dependencies.
LadybugDB.Nativemeta-package depends on all five per-RID packages.win-x64,linux-x64,linux-arm64,osx-x64,osx-arm64.what makes the slim, single-RID install possible.
Build pipeline (
cake/)LadybugDB.Build.csproj+BuildContext.cs(which also hosts theMainentry point), and the pipeline tasks under
Tasks/(Pipeline.csfor the small tasks +VerifyPackagesTask.cs). Bootstrap withbuild.ps1/build.sh.Clean,Restore,BuildManaged,Test,FetchNatives,PackManaged,PackRuntimes,PackNativeMeta,VerifyPackages,Pack,Default.BuildContextis the single source of truth for the RID set and the RID -> (release asset, library)mapping.
EnsureNativeStagedreuses a locally-built native if present, otherwise downloads the pinnedengine release asset (via
gh) and extracts the canonical library (pulling the real shared object outof the
.so/.dylibsymlink chain, since NuGet doesn't preserve symlinks).cake/native/LadybugDB.Native.Runtime.csproj,packed once per RID). The meta-package is a nuspec template (
cake/native/LadybugDB.Native.nuspec)with version/commit substituted at pack time. All packing is
dotnet-only (no nuget.exe / mono).VerifyPackagesasserts the managed assemblies, every per-RID payload, and the meta's dependency set,so a silent packaging regression fails the build instead of shipping a broken package.
Versioning
-alpha.Nprerelease suffix while indevelopment. Current default:
0.17.0-alpha.1.version.txtat the binding root - read byBuildContext, the managednuget-package.props, and both CI workflows. Bump the alpha (or the engine) there with no code change.--prerelease ""cuts a stable build equal to the engine version;--package-version <v>overridesexactly (the release workflow passes the
v*git tag).CI / release
ci.ymlandrelease.ymlnow invoke the pipeline (dotnet run --project cake/... -- --target ...)instead of inline shell.
ci.ymlruns atestmatrix (linux-x64 + win-x64) and apacksmoke;release.ymlruns the linux-x64 test gate, packs + verifies, then publishes all packages via OIDC.Docs
AGENTS.md(Packaging).Consumption
Validation
v0.17.0):--target Packproduced and verified all 7packages as
0.17.0-alpha.1(correct layouts; meta pins all five per-RID deps; no stray references);--target Testpassed 28/28 with the native loaded (no skips).Next steps / TODO
Maintainer actions before first publish:
releaseGitHub environment onLadybugDB/ladybug-dotnetand add secretNUGET_USER= the nuget.org profile name (NOT email).The
publishjob declaresenvironment: releaseandNuGet/login@v1readssecrets.NUGET_USER, sowithout these the publish step fails with a 403/auth error.
release.ymlviaworkflow_dispatchto confirm the linux-x64 gate +all-RID download/pack on CI (proven locally on win-x64 so far).
Follow-ups (can land later):
-alpha.Nsuffix as the binding stabilizes; drop it for the first stablev0.17.0.dataset/tinysnb.