Development
Working on virtufin-workers itself. Covers the build pipeline, the test layout, the CI surface, and the contribution conventions.
Build pipeline
The repo has two build entry points: per-worker (e.g. HttpGetWorker's scripts/build_*.py and scripts/build_both.py) and shared (@common/scripts/build_*.py).
The shared scripts:
- build_managed.py — produces a managed-only nupkg.
- build_aot.py — produces an AOT-only nupkg (requires Docker).
- publish.py — uploads the nupkg to the Gitea NuGet feed.
The worker-local scripts wrap the shared ones and set the per-worker paths (the managed and AOT csproj locations, the config.json path, the canonical build/ output dir).
The build script is runnable locally:
# Managed-only
python3 HttpGetWorker/scripts/build_managed.py
# AOT-only (requires Docker)
python3 HttpGetWorker/scripts/build_aot.py
# Both (single nupkg with both layouts)
python3 HttpGetWorker/scripts/build_both.py
Tests
HttpGetWorker/tests/Virtufin.Worker.HttpGetWorker.Tests/ is a C# xunit test project for the managed path only — Fact tests covering the success path, error handling (missing url, non-2xx status), content-type fallback, and correlationId propagation. The tests instantiate the worker directly and call ProcessAsync.
The AOT path has no unit tests in this repo — the same handler logic is shared with the managed target and covered there; the AOT shim itself is a thin [UnmanagedCallersOnly] wrapper with no independent logic to test. The virtufin-workmanager repo has unit tests for the NativeDllEngine.LoadFromNupkg flow, but those test the engine, not the worker.
CI
Each worker has its own .github/workflows/<workername>-nuget.yaml, a thin
caller of the shared virtufin/common/.github/workflows/worker-nuget-common.yaml
reusable workflow: on push to master (path-filtered to that worker's
directory), it runs the worker's tests, builds (managed-only, or
managed+NativeAOT via Docker when the caller sets ships_native: true),
and publishes to the Gitea NuGet feed. This is the actual publish path now
— see AGENTS.md's "Build & publish a worker" section.
/.github/workflows/docs.yaml (calls common/.github/workflows/docs-common.yaml@master with docs_repo: virtufin/workers-docs) and /.github/workflows/docs-lint.yaml (calls docs-lint-common.yaml@master) are the doc-site CI surfaces.
Conventions
scripts/build_managed.pyandscripts/build_aot.pyare thin pass-through wrappers — the real logic is in@common/scripts/build_*.py. The wrapper just sets paths.- Both csproj files (
Managed/andNative/) share the same<AssemblyName>so the nupkg's single<virtufinLibrary>value resolves to either the.dllor the.sodepending on which engine loads it. - The AOT csproj's
<Compile Include="..\...Managed\Logic.cs" Link="Logic.cs" />links the shared handler logic from the managed project dir. Path is relative to the AOT csproj's location, so no absolute paths. - NuGet auth is via
VIRTUFIN_REGISTRY_USER/VIRTUFIN_REGISTRY_TOKENenv vars; the worker scripts don't read~/.docker/config.jsonfor NuGet creds (only for Docker). The credentials are provided by the CI runner or the dev shell.
See also
- Build Script —
build_managed.py+build_aot.py+build_both.pyreference - Troubleshooting — common build/load failures and how to diagnose them