Portable WSLC backend for net10.0, Testcontainers-parity connection strings, repo renamed to containers - #3
Conversation
Purview.Containers.Wsl is now multi-target: net10.0 ships a portable facade and
net10.0-windows10.0.19041.0 ships the implementation (compiled against the
Microsoft.WSL.Containers projection, which is a net8.0-windows asset). A
platform-neutral net10.0 project can therefore reference the WSL backend and get
WSLC on a Windows host and Docker elsewhere through auto - no target-framework or
configuration change. This also corrects the docs, which claimed WSLC required a
.NET 11 Windows project.
- facade (WslPayload) loads the Windows build from a wslc/ payload into a
dedicated AssemblyLoadContext and delegates through IContainerBackend; it reports
wsl unavailable on non-Windows or when the payload is absent, so selection falls
through to Docker. Windows-targeting projects bind the implementation directly
and are unchanged.
- packaging: the implementation, the WSLC projection, its Windows SDK
dependencies and the native SDK are packed under payload/win-{x64,arm64}; the
buildTransitive targets copy the matching folder for a platform-neutral consumer
on Windows.
- guards: PCC0001 now accepts any .NET 10+ target (Windows 10.0.19041.0+ or
platform-neutral); PCC0002 still rejects a 32-bit Windows consumer.
- selection: a new optional IContainerBackendPreference.AutoPriority makes auto
prefer WSLC (0) over Docker (100) deterministically, instead of relying on the
MSBuild props-import order.
- spikes: DynamicLoadSpike (phase 0 feasibility) and PortableConsumerSpike
(acceptance) under spikes/.
- tests/docs: consumer contract, packaging, backends and module READMEs updated;
verify-consumers gains a portable case and updates the changed expectations.
Validated: build 0 warnings; unit 98/98; Wsl integration 27/27; verify-consumers
19/19; pipeline-pack-validate 20/20 packages valid; csharpier clean.
Match the Testcontainers SQL Server module: the generated connection string now sets Database=master by default, configurable with WithDatabase(...). Previously it omitted the catalog entirely, so consumers that expect Database=master (as Testcontainers produces) had to add it themselves.
- rename every repository reference from purview-dev/wsl-containers to purview-dev/containers (package.json, mkdocs.yml, README, docs, the package READMEs and PackageProjectUrl) - describe the service modules as running on WSL Containers or Docker (they are backend-neutral) and refresh the WSL, Docker and abstractions descriptions - broaden the package tags (docker for the modules, wslc/testcontainers for the WSL backend, docker/wsl for the abstractions) - rename the npm package to purview-containers and point homepage/bugs there
One-time integration run - proves the Docker path works without WSLCThe shared PR pipeline filters to
Each suite skips itself when its runtime is unreachable ( This is a deliberate one-off; the pipeline filter is unchanged. |
The umbrella README linked the version badge and its link to Purview.Containers.Wsl (the Windows-only WSLC backend). Point both at Purview.Containers, the entry point for the library.
The shared pipeline filters to [Category=Unit] because the WSLC suites need a Windows host, and the Docker integration suite projects inherited the Windows test TFM, so they never ran anywhere in CI. Make Docker.IntegrationTests and Modules.DockerIntegrationTests target net10.0 (they need only a reachable daemon) and add an integration-docker job to pr.yml that runs them on ubuntu-latest. That job is the standing proof the library and every service module work off Windows/WSL. The two projects also remove the SDK's automatic SharedTestingFramework reference, which is WSLC/Windows-only and nothing in them uses.
Docker integration now runs in the PR buildAdded an Latest run (
The WSLC suites still run only on a WSLC host; the shared pipeline filter stays |
The WSLC integration suites need a Windows host with WSL Containers, which no hosted runner provides, so they cannot run on pull_request. Add integration-wsl.yml, a workflow_dispatch-only workflow that runs Wsl.IntegrationTests and the seven service-module suites one project at a time on a self-hosted Windows runner carrying the custom wslc label, after checking 'wsl --version' and 'wslc version' so a mis-provisioned runner fails fast. Declare the custom label in .github/actionlint.yaml so actionlint validates the workflow, and document the runner prerequisites in docs/wiki/Testing.md.
GenericBuilder_WithTheDockerBackendSelected_StartsAContainer ran /bin/echo selected and then asserted ContainerState.Running. On a fast runner the echo container exits before the state is read, so the assertion flaked (observed on a CI run, 6/7). Use a long-lived command so the container is reliably running.
Manual WSLC workflow (self-hosted) + a flake fix
Trigger: Actions -> Integration (WSL Containers) -> Run workflow, or Flake fix. The previous run failed |
The same test project should run on WSLC on a Windows machine and Docker everywhere else without a backend choice in code or environment. That was only described in pieces across Getting-Started, Backends and Modules. Add docs/wiki/Using-in-Your-Tests.md with the copy-paste project file (net10.0, both backends, Redis and PostgreSQL), the test, and a per-host table; link it from the sidebar, index and Getting Started. Add samples/getting-started/AutoSample: a net10.0 project referencing both backends and two modules that lets automatic selection choose (it assembles the wslc/ payload by hand, as a package consumer gets it from Purview.Containers.Wsl buildTransitive). Wire it into the solution, add `just sample-auto`, and update the samples README. Guard the documented shape with verify-consumers case 20 (net10.0 + two modules + both backends); the RequireText check now accepts multiple patterns so it asserts both registrations are generated. Update the Consumer-Requirements count to twenty.
Zero-config "auto" story: docs, sample and a guarded case
Verified end to end on this Windows host: AutoSample reported Latest run |
…umbrella
BREAKING CHANGE: the abstractions package is renamed to Purview.Containers.Core. A
package reference to Purview.Containers now means the new umbrella bundle. Consumer
source is unchanged (the namespace stays Purview.Containers).
Purview.Containers is the dependency root (IContainerBackend lives there) so it cannot
reference the backends; a TUnit-style split keeps that direction and puts the bundle at
the name consumers reach for:
- src/src/Containers -> src/src/Core (Core.csproj; SDK derives PackageId and AssemblyName
Purview.Containers.Core and RootNamespace Purview.Containers, so no consumer using changes)
- buildTransitive assets move to Purview.Containers.Core.{props,targets} so NuGet still
auto-imports them
- new src/src/Containers/Containers.csproj: umbrella referencing Core, Wsl and Docker;
no code and no buildTransitive of its own (the dependencies flow transitively)
One reference now gives the whole auto setup: a net10.0 project with Purview.Containers
and the modules runs on WSLC on Windows and Docker elsewhere, no registration and no
environment variable.
Docs (Architecture, Consumer-Requirements, Home, Packaging, Modules, Getting-Started,
Using-in-Your-Tests, README, AGENTS, package READMEs) describe the split and present the
umbrella as the zero-config default, with Core plus a single backend as the lean route for
Linux-only CI. purview-build.json gains purview.containers.core and trims
purview.containers to the umbrella. verify-consumers case 13 targets Core and a new case
21 references only the umbrella. AutoSample now references the umbrella project.
|
| Package | Role |
|---|---|
Purview.Containers.Core |
the backend-neutral abstractions (was Purview.Containers) |
Purview.Containers |
new umbrella: depends on Core + Wsl + Docker; no code of its own |
Purview.Containers.Wsl / .Docker / the modules |
unchanged ids |
A reference to Purview.Containers used to mean the abstractions; it now means the bundle. Consumer source is unchanged — the namespace stays Purview.Containers (the SDK strips the .Core segment), so only the package id moves. Breaking for prerelease consumers, flagged as BREAKING CHANGE.
The registry stays the dependency root (IContainerBackend lives in Core), so Core is the thing everything depends on and the umbrella sits on top — no cycle.
Why it is nice: one reference gives the whole auto setup. Purview.Containers + a module on a net10.0 project runs WSLC on Windows and Docker elsewhere, no registration and no env var (the backends buildTransitive assets flow transitively through the umbrella).
Validation:
- build 0 warnings; unit 100/100
just verify-consumers21/21 (new case 21 references only the umbrella and asserts both registrations are generated; case 13 retargeted toPurview.Containers.Core)just pipeline-pack-validate✓ 22/22 packages valid- AutoSample now references the umbrella project and still picks WSLC (
wslusable /dockerusable -> selectedwsl, PONG + accepting connections) - CI run
36933403528: success (Build and test + Integration (Docker))
Summary
Portable WSLC backend (headline)
Purview.Containers.Wslis now multi-target:net10.0- a portable facade that loads the Windows implementation from awslc/payload at runtime and reports
wslunavailable everywhere else, soautoselection falls through to Docker.net10.0-windows10.0.19041.0- the WSLC implementation (compiled against theMicrosoft.WSL.Containersprojection, which is anet8.0-windowsasset).A plain
net10.0test project can therefore reference the WSL backend and get WSLC on a Windowsdeveloper machine and Docker on a Linux CI runner with no target-framework or configuration change.
This corrects the docs, which claimed WSLC required a .NET 11 Windows project.
packed under
payload/win-{x64,arm64}; thebuildTransitivetargets copy the matching folder for aplatform-neutral consumer on Windows.
PCC0001accepts any .NET 10+ target (Windows 10.0.19041.0+ or platform-neutral);PCC0002still rejects a 32-bit Windows consumer.
IContainerBackendPreference.AutoPrioritymakesautoprefer WSLC (0) overDocker (100) deterministically, instead of relying on the MSBuild props-import order.
Testcontainers connection-string parity
SQL Server
GetConnectionString()now setsDatabase=masterby default (configurable with the newWithDatabase(...)), matchingTestcontainers.MsSql. The other modules already matched (Redishost:port, PostgreSQL/MySQL client strings, RabbitMQamqp://, Azurite, NATSnats://), anddocs/wiki/Modules.mdnow documents the per-module connection-string shape.Metadata and repository rename
purview-dev/wsl-containers->purview-dev/containers; every referenceupdated (package.json, mkdocs.yml, README, docs, package READMEs,
PackageProjectUrl).purview-containers.Validation
dotnet build src/WSLTestContainers.slnx- 0 warnings, 0 errorsjust verify-consumers- 19/19just pipeline-pack-validate- 20/20 packages validdotnet csharpier check .- cleanAdds Phase 0/acceptance spikes under
spikes/DynamicLoadSpikeandspikes/PortableConsumerSpike.