Skip to content

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.py and scripts/build_aot.py are thin pass-through wrappers — the real logic is in @common/scripts/build_*.py. The wrapper just sets paths.
  • Both csproj files (Managed/ and Native/) share the same <AssemblyName> so the nupkg's single <virtufinLibrary> value resolves to either the .dll or the .so depending 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_TOKEN env vars; the worker scripts don't read ~/.docker/config.json for 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.py reference
  • Troubleshooting — common build/load failures and how to diagnose them