Summary
Introduce a generic artifact management system for Orchestrator that provides convenient, built-in handling for all types of build output. Instead of treating output as a single opaque blob, artifacts are typed, manifested, and processed through configurable pipelines.
The system provides convenient defaults — test results automatically report to GitHub Checks, images get baseline-diffed, metrics get trended — while remaining fully extensible for project-specific output types.
Think of it as: every build produces an artifact manifest describing what was created, and each artifact type has a processing pipeline that knows how to handle it.
Motivation
Currently Orchestrator treats build output as a single artifact — typically a game build. But real production workflows produce many types of output that each need different handling:
- Test results should be parsed, reported to GitHub Checks as inline annotations, and archived
- Screenshots / render captures should be thumbnailed, diffed against baselines, and attached to PRs
- Server builds need separate artifact paths, potentially different upload destinations
- Exported data files (CSV, JSON, binary) need validation and may feed downstream pipelines
- Build metrics (compile times, asset sizes, shader variants) should be tracked over time
- Logs should be structured, searchable, and linked to specific build phases
Each output type has different storage needs, retention policies, post-processing steps, and CI integration points. Treating everything as a single artifact blob loses all of this.
Proposed Features
Output Type Declarations
Declare what outputs a build produces:
- uses: game-ci/unity-builder@v4
with:
targetPlatform: StandaloneLinux64
outputTypes: build,test-results,metrics,images
Output Type Registry
Built-in output types with extensible registration:
| Type |
Default Path |
Post-Processing |
CI Integration |
build |
./Builds/{platform}/ |
Compress, upload |
Artifact link on Check |
test-results |
./TestResults/ |
Parse JUnit/NUnit XML |
Inline annotations on PR |
server-build |
./Builds/{platform}-server/ |
Compress, upload |
Separate artifact link |
data-export |
./Exports/ |
Validate schema |
Artifact link |
images |
./Captures/ |
Thumbnail, baseline diff |
Image diff on PR |
logs |
./Logs/ |
Structure, index |
Searchable in Check details |
metrics |
./Metrics/ |
Aggregate, trend |
Dashboard / Check summary |
coverage |
./Coverage/ |
Generate report |
Coverage badge / PR comment |
Output Manifest
Every build produces a structured manifest describing all outputs:
{
"buildGuid": "abc-123",
"timestamp": "2024-01-15T10:30:00Z",
"outputs": [
{
"type": "build",
"path": "./Builds/StandaloneLinux64/",
"size": 524288000,
"hash": "sha256:abc...",
"metadata": {
"platform": "StandaloneLinux64",
"scripting": "IL2CPP"
}
},
{
"type": "test-results",
"path": "./TestResults/editmode-results.xml",
"format": "nunit3",
"summary": {
"total": 342,
"passed": 340,
"failed": 1,
"skipped": 1
}
},
{
"type": "images",
"path": "./Captures/",
"files": ["main-menu.png", "gameplay-01.png"],
"metadata": {
"resolution": "1920x1080",
"captureMode": "screenshot"
}
},
{
"type": "metrics",
"path": "./Metrics/build-metrics.json",
"metadata": {
"compileTime": 45.2,
"assetCount": 12500,
"buildSize": 524288000
}
}
]
}
Per-Type Post-Processing Pipelines
Each output type has a configurable post-processing pipeline:
outputPipelines:
test-results:
- parse: nunit3
- report: github-checks
- archive: s3
images:
- thumbnail: { maxWidth: 256 }
- diff: { baseline: ./Baselines/ }
- report: github-pr-comment
metrics:
- aggregate: { groupBy: platform }
- trend: { history: 30 }
- report: github-check-summary
Custom Output Types
Projects can register custom output types:
customOutputTypes:
- name: addressables-catalog
path: ./ServerData/
postProcess:
- validate: json-schema
- upload: cdn
- name: localization-export
path: ./Exports/Localization/
postProcess:
- validate: csv
- archive: s3
GitHub Integration
Output types integrate with GitHub surfaces:
- Test results → GitHub Check annotations (inline failure markers on PR files)
- Images → PR comment with image grid and baseline diffs
- Metrics → Check run summary with trend graphs
- Coverage → PR comment with coverage delta
- Build artifacts → Check run artifact links
New Inputs
| Input |
Description |
outputTypes |
Comma-separated output types to collect |
outputManifestPath |
Where to write the output manifest JSON |
outputPipelines |
YAML defining per-type post-processing |
customOutputTypes |
YAML defining project-specific output types |
imageBaselinePath |
Path to baseline images for visual diff |
metricsHistory |
Number of builds to retain for trend tracking |
Implementation Notes
- New service:
OutputService in src/model/orchestrator/services/output/
- Output manifest generated at end of build, before post-build hooks
- Per-type post-processors are pluggable (similar to provider pattern)
- Test result parsing supports NUnit3 (Unity default), JUnit, and custom formats
- Image diffing uses pixel-level comparison with configurable threshold
- Metrics trending requires a storage backend (S3, rclone, or local)
- Custom output types loaded from
.game-ci/output-types.yml or passed as input
Related
Implementation
| PR |
Description |
Status |
| #798 |
feat(orchestrator): generic artifact system |
Draft — 36+ tests |
| game-ci/documentation#538 |
docs: build output system page |
Draft |
Tracking
Summary
Introduce a generic artifact management system for Orchestrator that provides convenient, built-in handling for all types of build output. Instead of treating output as a single opaque blob, artifacts are typed, manifested, and processed through configurable pipelines.
The system provides convenient defaults — test results automatically report to GitHub Checks, images get baseline-diffed, metrics get trended — while remaining fully extensible for project-specific output types.
Think of it as: every build produces an artifact manifest describing what was created, and each artifact type has a processing pipeline that knows how to handle it.
Motivation
Currently Orchestrator treats build output as a single artifact — typically a game build. But real production workflows produce many types of output that each need different handling:
Each output type has different storage needs, retention policies, post-processing steps, and CI integration points. Treating everything as a single artifact blob loses all of this.
Proposed Features
Output Type Declarations
Declare what outputs a build produces:
Output Type Registry
Built-in output types with extensible registration:
build./Builds/{platform}/test-results./TestResults/server-build./Builds/{platform}-server/data-export./Exports/images./Captures/logs./Logs/metrics./Metrics/coverage./Coverage/Output Manifest
Every build produces a structured manifest describing all outputs:
{ "buildGuid": "abc-123", "timestamp": "2024-01-15T10:30:00Z", "outputs": [ { "type": "build", "path": "./Builds/StandaloneLinux64/", "size": 524288000, "hash": "sha256:abc...", "metadata": { "platform": "StandaloneLinux64", "scripting": "IL2CPP" } }, { "type": "test-results", "path": "./TestResults/editmode-results.xml", "format": "nunit3", "summary": { "total": 342, "passed": 340, "failed": 1, "skipped": 1 } }, { "type": "images", "path": "./Captures/", "files": ["main-menu.png", "gameplay-01.png"], "metadata": { "resolution": "1920x1080", "captureMode": "screenshot" } }, { "type": "metrics", "path": "./Metrics/build-metrics.json", "metadata": { "compileTime": 45.2, "assetCount": 12500, "buildSize": 524288000 } } ] }Per-Type Post-Processing Pipelines
Each output type has a configurable post-processing pipeline:
Custom Output Types
Projects can register custom output types:
GitHub Integration
Output types integrate with GitHub surfaces:
New Inputs
outputTypesoutputManifestPathoutputPipelinescustomOutputTypesimageBaselinePathmetricsHistoryImplementation Notes
OutputServiceinsrc/model/orchestrator/services/output/.game-ci/output-types.ymlor passed as inputRelated
Implementation
Tracking