High-Level Architecture
The result: zero runtime reflection, full IntelliSense, compile-time safety, and multi-version awareness — all from a single [GitLabCiBundle] attribute.
The Four-Project Architecture
GitLab.Ci.Yaml follows a proven four-project pattern used across the FrenchExDev.Net ecosystem (also used by DockerCompose.Bundle and BinaryWrapper):
GitLab.Ci.Yaml/
src/
FrenchExDev.Net.GitLab.Ci.Yaml/ net10.0 Main library
FrenchExDev.Net.GitLab.Ci.Yaml.Attributes/ ns2.0+net10 Marker attribute
FrenchExDev.Net.GitLab.Ci.Yaml.Design/ net10.0 Schema downloader (Exe)
FrenchExDev.Net.GitLab.Ci.Yaml.SourceGenerator/ ns2.0 Roslyn incremental SG
test/
FrenchExDev.Net.GitLab.Ci.Yaml.Tests/ net10.0 xUnit testsGitLab.Ci.Yaml/
src/
FrenchExDev.Net.GitLab.Ci.Yaml/ net10.0 Main library
FrenchExDev.Net.GitLab.Ci.Yaml.Attributes/ ns2.0+net10 Marker attribute
FrenchExDev.Net.GitLab.Ci.Yaml.Design/ net10.0 Schema downloader (Exe)
FrenchExDev.Net.GitLab.Ci.Yaml.SourceGenerator/ ns2.0 Roslyn incremental SG
test/
FrenchExDev.Net.GitLab.Ci.Yaml.Tests/ net10.0 xUnit tests| Project | Role | Target | Dependencies |
|---|---|---|---|
| Attributes | [GitLabCiBundle] attribute that triggers source generation |
netstandard2.0 + net10.0 | None |
| Design | CLI that downloads versioned CI schemas from GitLab releases API | net10.0 (Exe) | Wrapper.Versioning |
| SourceGenerator | Reads JSON schemas as AdditionalFiles, merges versions, emits C# models + builders |
netstandard2.0 | Microsoft.CodeAnalysis, Builder.SourceGenerator.Lib |
| Main Library | Contains generated code (via SG), hand-written YAML reader/writer, version type, contributor interface | net10.0 | Result, Builder, YamlDotNet |
| Tests | 20 tests covering models, builders, writer, reader, version parsing | net10.0 | xUnit, Shouldly |
This separation achieves several goals:
- No runtime schema parsing — all code is generated at compile time
- No build-time downloads — schemas are pre-downloaded and committed to source control
- Testable in isolation — each project has a clear boundary and responsibility
- Minimal attribute dependency — the Attributes project targets netstandard2.0 with zero dependencies
- Clean public API — the main library exposes only generated models, builders, and hand-written infrastructure
How It All Fits Together
Design time downloads JSON schemas from GitLab release tags — one schema per minor version. Build time feeds those JSON files to a Roslyn incremental source generator that parses schemas, merges versions, computes version annotations, and emits sealed model classes, fluent builders, and version metadata. Runtime provides YAML serialization, deserialization, a contributor pattern for modular composition, and version comparison utilities.
Dependency Graph
The dependency flow is strictly one-directional. The Design project has no relationship with the source generator — it produces JSON files that the generator consumes as AdditionalFiles. The Attributes project has zero dependencies, making it safe to reference from any target framework. The SourceGenerator project targets netstandard2.0 (required by Roslyn) and references only Microsoft.CodeAnalysis and Builder.SourceGenerator.Lib.