CVOYA graph Build System Guide
This document explains the CVOYA graph build configurations, version management, and development workflows.
π Quick Start
Required Packages
To get started, install the Neo4j provider package (required):
dotnet add package Cvoya.Graph.Neo4j
Optionally, add the analyzers package for extra compile-time validation (recommended):
dotnet add package Cvoya.Graph.Analyzers
Essential Commands
# Development build (fastest, project references)
dotnet build --configuration Debug
# Test package references locally
dotnet msbuild eng/PackageValidation.proj -target:Validate
# Cut a release (--plan previews the tag without pushing)
./scripts/release.sh 1.2.3
# Build one production package (pack builds first by default)
dotnet pack src/Graph/Graph.csproj --configuration Release
# Run performance benchmarks
./scripts/run-benchmarks.sh
# Run local CodeQL analysis
./scripts/run-codeql.sh
π¦ Build Configurations
CVOYA graph uses four distinct build configurations optimized for different scenarios:
| Configuration | Project Refs | Optimizations | Packages | VERSION Required | Use Case |
|---|---|---|---|---|---|
| Debug | β Yes | β No | β No | β No | Development & debugging |
| Benchmark | β Yes | β Yes | β No | β No | Performance testing |
| LocalFeed | β Yes | β Yes | β Yes | β No | Local package testing |
| Release | β Default | β Yes | Via pack |
β Yes | Production package builds |
Configuration Details
Debug Configuration
- Purpose: Day-to-day development
- Speed: Fastest builds (no optimizations)
- Dependencies: Direct project references
- Packages: None generated
- Usage:
dotnet build --configuration Debug
Benchmark Configuration
- Purpose: Performance testing and benchmarking
- Speed: Optimized builds with project references
- Dependencies: Direct project references (fast rebuilds)
- Packages: None generated
- Usage:
dotnet msbuild -target:BuildBenchmark
LocalFeed Configuration
- Purpose: Building the local package set before package-reference validation
- Speed: Optimized builds with fast project references
- Dependencies: Direct project references (fast builds)
- Packages: Generated in the configured package output directory
- Usage:
dotnet build --configuration LocalFeed
Release Configuration
- Purpose: Production builds and publishing
- Speed: Fully optimized
- Dependencies: Project references by default; the package-validation orchestrator explicitly sets
UsePackageReferences=true - Packages: Generated by
dotnet pack; a normal Release build does not pack - Usage:
dotnet pack src/Graph/Graph.csproj --configuration Release
π·οΈ Version Management
CVOYA graph releases are tag-authoritative: the pushed tag is the version. Nothing in CI writes or stamps a version, which is what keeps package versions consistent and prevents accidental releases.
Version Scheme
MAJOR.MINOR.PATCH[-(alpha|beta|rc).YYYYMMDD[.N]]
# Stable release
1.2.3
# Date-anchored pre-releases (the .1 is a same-day counter)
1.2.3-alpha.20260716
1.2.3-rc.20260716.1
Creating Releases
scripts/release.sh computes the version, pushes the tag, and release.yml reads
it back β nothing writes a version to a file, so nothing can be stamped twice.
# Preview the computed tag without pushing anything
./scripts/release.sh 1.2.3 --pre alpha --plan
# Cut a stable release -> v1.2.3
./scripts/release.sh 1.2.3
# Cut a date-anchored pre-release -> v1.2.3-alpha.20260716
./scripts/release.sh 1.2.3 --pre alpha
# ...and make it the current Latest on GitHub
./scripts/release.sh 1.2.3 --pre alpha --latest
The base version is positional and pre-release suffixes come from --pre β they
are never typed by hand. See ./scripts/release.sh --help for the full option
list, and release-process.md for the full process.
The VERSION file
VERSION is the development default for untagged local and CI builds, not the
release source of truth. Editing it does not cut a release, and cutting a release
does not edit it. release.yml passes the tagβs version to the pack job as
GRAPH_RELEASE_VERSION, which Directory.Build.props prefers over the file.
Publishing a Release
Publishing is entirely tag-triggered β there is no manual publish step:
- Run
./scripts/release.sh X.Y.Z [--pre alpha|beta|rc]from a checkout whose HEAD is onorigin/main. It computes the version, runs the pre-flight checks, and pushes thevX.Y.Ztag. .github/workflows/release.ymlreads the version off the tag and rejects it if it doesnβt match the version scheme, runs the full test suite including the Neo4j and Apache AGE provider tests, packs every package, publishes to NuGet using Trusted Publishing (OIDC β no stored API key), attests build provenance, and creates the GitHub Release with generated notes.release.shwatches that run and then verifies every published package actually resolves on nuget.org before reporting success.
See docs/release-process.md for the full process, including the one-time NuGet Trusted Publishing portal setup.
π Development Workflows
Standard Development Workflow
# 1. Regular development (fastest)
dotnet build --configuration Debug
# 2. Run tests
dotnet test --configuration Debug
# 3. Performance testing when needed
dotnet build --configuration Benchmark
./scripts/run-benchmarks.sh
Local CodeQL Analysis
CVOYA graphβs GitHub workflow runs CodeQL for GitHub Actions, C#, and Ruby with
the security-and-quality query suite. To catch those findings before pushing,
install the CodeQL CLI and run:
./scripts/run-codeql.sh
The script writes one SARIF file per language under artifacts/codeql/results/.
It downloads the Actions, C#, and Ruby query packs by default so local scans use
the same query suite as .github/workflows/codeql.yml. The default CodeQL build
mode is none, which is the required portable local gate. In that mode, the
script analyzes a disposable source copy and temporary databases outside the
checkout so CodeQL dependency probing cannot rewrite repository files.
To trace the same LocalFeed and Release builds used by the GitHub workflow,
use manual build mode:
./scripts/run-codeql.sh --build-mode manual
Manual mode is optional because it relies on CodeQL compiler tracing support for
the local platform and .NET toolchain. If manual mode completes the build but
CodeQL exits with βcould not process anyβ C# source, rerun the default command
without --build-mode manual. A successful default run satisfies the local
CodeQL gate; capture the manual-mode CodeQL version and db/csharp/log path in
PR notes only if the manual failure is relevant.
For a stricter local gate:
./scripts/run-codeql.sh --fail-on-alerts
To include CodeQL in the full build-system validation pass:
./scripts/validate-build.sh --codeql
Release Preparation Workflow
# 1. Verify the release build works
dotnet build --configuration Release
# 2. Run the full test suite
dotnet test --configuration Release
# 3. Preview the tag that would be cut
./scripts/release.sh 1.2.3 --plan
# 4. Cut it β release.sh pushes the tag, watches release.yml, and verifies
# the published packages resolve on nuget.org
./scripts/release.sh 1.2.3
release.sh requires a clean checkout exactly at the refreshed origin/main
commit; it refuses stale, divergent, or dirty state. Steps 1 and 2 are a local
smoke test β release.yml reruns the full suite against the tagged commit
regardless.
Package Testing Workflow
Package-reference validation has one repository-level owner:
dotnet msbuild eng/PackageValidation.proj -target:Validate
The orchestrator starts from clean repository-owned state, restores and builds the LocalFeed package set, explicitly packs the analyzer projects, verifies the exact nine-package inventory and every packaged assemblyβs version metadata with scripts/verify-package-set.sh, and then restores/builds the solution with UsePackageReferences=true. eng/package-validation.NuGet.config maps Cvoya.* to the generated feed and everything else to NuGet.org.
All package, feed, global-packages, HTTP-cache, scratch, and plugin-cache paths live under artifacts/package-validation/. The workflow does not add or remove user-level NuGet sources and does not read, clear, or write the userβs global NuGet caches.
The inventory check requires bash and jq on PATH; this is the same toolchain used by the repository scripts on Linux, macOS, and Git-for-Windows/GitHub-hosted Windows environments. All path construction and project classification inside MSBuild use OS-native normalized paths.
The compatibility wrappers delegate to the same orchestrator:
./scripts/setup-local-feed-msbuild.sh
./scripts/cleanup-local-feed.sh
π οΈ Available MSBuild Targets
Version Management
# Cut a release (pushes the tag; --plan to preview)
./scripts/release.sh X.Y.Z [--pre alpha|beta|rc]
# Show the version the current tree would build as
dotnet msbuild -target:ShowVersion
Build Commands
# Build specific configurations
dotnet build --configuration Debug
dotnet build --configuration Benchmark
dotnet build --configuration Release
Local Package Testing
# Pack and verify the repository-scoped local feed
dotnet msbuild eng/PackageValidation.proj -target:PrepareLocalFeed
# Build the solution with locally produced package references
dotnet msbuild eng/PackageValidation.proj -target:BuildWithPackageReferences
# Run the complete required gate
dotnet msbuild eng/PackageValidation.proj -target:Validate
# Remove only repository-scoped validation state
dotnet msbuild eng/PackageValidation.proj -target:Clean
Cleanup Commands
# Clean build outputs
dotnet clean
π Directory Structure
graphmodel/
βββ VERSION # Development default version for untagged builds
βββ Directory.Build.props # MSBuild configuration
βββ eng/
β βββ PackageValidation.proj # Local package-validation orchestrator
β βββ PackageVersionVerifier/ # Reads version metadata from packed DLLs
β βββ package-validation.NuGet.config
βββ artifacts/package-validation/ # Repository-scoped feed, packages, and caches
βββ scripts/
βββ release.sh # Release orchestration (tag, watch, verify)
βββ run-benchmarks.sh # Benchmark runner
βββ cleanup-local-feed.sh # Legacy cleanup script
π¨ Error Prevention
Common Errors and Solutions
βVERSION file is required for package generationβ
# Supply a version for this package without editing VERSION
GRAPH_RELEASE_VERSION=1.2.3 dotnet pack src/Graph/Graph.csproj --configuration Release
βPackage reference could not be resolvedβ
# Recreate the isolated feed and package-reference restore
dotnet msbuild eng/PackageValidation.proj -target:Validate
A package whose contents donβt match its version
Use the normal pack command when building and packing in one step:
GRAPH_RELEASE_VERSION=1.2.3 dotnet pack --configuration Release -o ./artifacts src/Graph/Graph.csproj
--no-build is reserved for flows that already built with the same
GRAPH_RELEASE_VERSION, such as release.yml. The complete local package gate
also verifies the NuGet manifest and the assembly, file, and informational
versions inside every package:
dotnet msbuild eng/PackageValidation.proj -target:Validate
Build cache issues
# Solution: Clean and rebuild
dotnet clean
dotnet build --configuration Release
π§ Advanced Configuration
Custom Build Properties
# Force package generation in any configuration
dotnet build -p:ForcePackageGeneration=true
# Override package output path
dotnet pack src/Graph/Graph.csproj --configuration Release -p:PackageOutputPath=/custom/path
CI/CD Integration
Releases are handled entirely by .github/workflows/release.yml, triggered by a
validated vX.Y.Z[-prerelease] tag β there is no CI step that stamps a version.
See docs/release-process.md.
π Best Practices
Development
- Use Debug configuration for daily development
- Use Benchmark configuration for performance testing
- Keep VERSION file in source control
- Test with Release configuration before publishing
Release Management
- Preview releases with
./scripts/release.sh X.Y.Z [--pre alpha|beta|rc] --plan - Let
release.shgenerate date-anchored prerelease versions; do not type tags by hand - Test Release configuration before publishing
- Never move an existing release tag; rerun its workflow or choose a new version
Performance
- Debug: Fastest for development
- Benchmark: Fast + optimized for testing
- Release: Optimized production builds and explicit packing
π Troubleshooting
Build Issues
- Check if VERSION exists for Release/package-validation builds.
- Clean and rebuild:
dotnet clean && dotnet build. - For package-reference failures, run
dotnet msbuild eng/PackageValidation.proj -target:Clean, then rerun-target:Validate.
Package Issues
- Remove repository package-validation state:
dotnet msbuild eng/PackageValidation.proj -target:Clean. - Rerun the complete package gate:
dotnet msbuild eng/PackageValidation.proj -target:Validate. - Inspect
artifacts/package-validation/; do not clear user-level NuGet caches.
Version Issues
- Check the resolved version:
dotnet msbuild -target:ShowVersion - Override it for one build:
GRAPH_RELEASE_VERSION=X.Y.Z dotnet build -c Release - Verify VERSION file format (single line, no extra whitespace)