You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Create the components that ADotNet is currently missing so that it can generate GitHub Actions
workflow YAML containing job-level strategy (matrix) and services (service containers).
These are required to generate acceptance-test workflows that run the same test suite across a build
matrix (e.g. sqlserver | postgres) with backing service containers.
The new components must be exposed through the existing GitHubPipelineBuilder / JobBuilder
fluent API (this is the convention used to build pipelines).
Hard requirement: the generated components MUST represent the full functionality offered by
GitHub Actions for strategy and services — not just the subset shown in the reference
example below. Model every documented key (see the "Full GitHub surface" checklist), even where the
reference workflow does not use it.
Background
A downstream project needs an acceptance-test workflow shaped like this (abbreviated):
Credentials — registry credentials for a service/container image.
Extend Strategy to add fail-fast, max-parallel, and matrix include / exclude.
(Recommended) a Matrix type to represent axis variables + include + exclude.
Add Services to Job as Dictionary<string, Service> (service id → definition).
2. Builders (ADotNet/Clients/Builders/)
Extend the existingGitHubPipelineBuilder / JobBuilder flow only — no new builder types
(no ServiceBuilder). Service and strategy configuration is added to the current builders:
JobBuilder.AddService(string id, Service service) — attach a service container to the job
(the caller constructs the Service model; add convenience overloads if helpful).
JobBuilder strategy helpers — e.g. WithMatrix(...), AddMatrixInclude(...), WithFailFast(bool), WithMaxParallel(int).
3. Tests (AdoNet.Tests.Unit/)
Unit tests for the new models' YAML serialization.
Tests for the new GitHubPipelineBuilder / JobBuilder additions (service + strategy methods).
End-to-end GitHubPipelineBuilder test proving a full matrix + services workflow serializes
to the expected YAML (see AdoNet.Tests.Unit/Clients/Builders/).
Full GitHub surface (must be represented — not limited to the example)
jobs.<job_id>.strategy
matrix — arbitrary axis variables: key: [values]
matrix.include — list of maps (combinations to add / extend, may add keys not in the axes)
matrix.exclude — list of maps (combinations to remove)
fail-fast — boolean (GitHub default is true)
max-parallel — integer
jobs.<job_id>.services.<service_id> (same schema as jobs.<job_id>.container)
image — string
credentials — { username, password }
env — map
ports — list of strings
volumes — list of strings ← missing from the reference example; still required
options — string
Because container and services.<id> share the identical schema, consider designing Service
so the same shape can be reused for a future job-level container component.
Reference component examples
These are illustrative of the shape/conventions expected (match existing YamlMember ordering and OmitDefaults usage). Extend as needed to reach full GitHub coverage.
publicclassService{[YamlMember(Order=0,Alias="image",DefaultValuesHandling=DefaultValuesHandling.OmitDefaults)]publicstringImage{get;set;}[YamlMember(Order=1,Alias="credentials",DefaultValuesHandling=DefaultValuesHandling.OmitDefaults)]publicCredentialsCredentials{get;set;}[YamlMember(Order=2,Alias="env",DefaultValuesHandling=DefaultValuesHandling.OmitDefaults)]publicDictionary<string,string>Environment{get;set;}[YamlMember(Order=3,Alias="ports",DefaultValuesHandling=DefaultValuesHandling.OmitDefaults)]publicList<string>Ports{get;set;}// Required for full GitHub coverage even though the reference workflow omits it:[YamlMember(Order=4,Alias="volumes",DefaultValuesHandling=DefaultValuesHandling.OmitDefaults)]publicList<string>Volumes{get;set;}[YamlMember(Order=5,Alias="options",DefaultValuesHandling=DefaultValuesHandling.OmitDefaults)]publicstringOptions{get;set;}}
// Extended Strategy — additive to the existing matrix support.publicclassStrategy{[YamlMember(Order=0,Alias="fail-fast",DefaultValuesHandling=DefaultValuesHandling.OmitDefaults)]publicbool?FailFast{get;set;}// nullable: GitHub defaults to true, so only emit when set[YamlMember(Order=1,Alias="max-parallel",DefaultValuesHandling=DefaultValuesHandling.OmitDefaults)]publicint?MaxParallel{get;set;}[YamlMember(Order=2,Alias="matrix",DefaultValuesHandling=DefaultValuesHandling.OmitDefaults)]publicMatrixMatrix{get;set;}}
// Matrix — axis variables plus include/exclude combinations.publicclassMatrix{// Axis variables, e.g. { "provider": ["sqlserver", "postgres"] }.// NOTE: in YAML these keys must appear as SIBLINGS of include/exclude (see considerations).publicDictionary<string,List<string>>Variables{get;set;}[YamlMember(Alias="include",DefaultValuesHandling=DefaultValuesHandling.OmitDefaults)]publicList<Dictionary<string,string>>Include{get;set;}[YamlMember(Alias="exclude",DefaultValuesHandling=DefaultValuesHandling.OmitDefaults)]publicList<Dictionary<string,string>>Exclude{get;set;}}
// Job — add the services map (service id -> definition).[YamlMember(Order=13,Alias="services",DefaultValuesHandling=DefaultValuesHandling.OmitDefaults)]publicvirtualDictionary<string,Service>Services{get;set;}
fail-fast default is true. The meaningful override is false. Use bool? (nullable) so an
unset value is omitted and an explicit false is emitted — a non-nullable bool + OmitDefaults
would silently drop false.
Matrix serialization. Base axis variables are dynamic keys that must be emitted as siblings
of include/exclude. YamlDotNet will not flatten a nested dictionary property automatically —
a custom representation (e.g. build a single Dictionary<string, object> where values are either List<string> for axes or List<Dictionary<string,string>> for include/exclude) or a custom
converter is likely needed.
Backward compatibility. The existing Strategy.Matrix is Dictionary<string, List<string>>,
which is public API. Changing its type is a breaking change — decide between (a) evolving Strategy
additively while preserving the current property, or (b) a versioned successor consistent with the
repo's V2/V3 component pattern.
Shared shape with container. Design Service so it can be reused for a future job-level container component (identical GitHub schema).
Acceptance criteria
Service and Credentials models created, covering the full GitHub services.<id> schema
(image, credentials, env, ports, volumes, options).
Strategy supports fail-fast, max-parallel, and matrix include / exclude (in addition to axes).
Job exposes a services map that serializes as service id -> definition.
Existing GitHubPipelineBuilder / JobBuilder extended with methods to add services and configure the strategy — no new builder types.
All new properties omit themselves from YAML when unset (OmitDefaults), consistent with existing models.
Unit tests: model serialization, the new builder methods, and an end-to-end GitHubPipelineBuilder test that reproduces the matrix + services workflow above.
Components represent the full GitHub feature set, not only the reference example.
Summary
Create the components that ADotNet is currently missing so that it can generate GitHub Actions
workflow YAML containing job-level
strategy(matrix) andservices(service containers).These are required to generate acceptance-test workflows that run the same test suite across a build
matrix (e.g.
sqlserver | postgres) with backing service containers.The new components must be exposed through the existing
GitHubPipelineBuilder/JobBuilderfluent API (this is the convention used to build pipelines).
Background
A downstream project needs an acceptance-test workflow shaped like this (abbreviated):
ADotNet cannot currently produce the
strategy(withinclude) orservicessections.Current state
StrategymatrixasDictionary<string, List<string>>include,exclude,fail-fast,max-parallelJob.StrategyOrder = 8)StrategyaboveservicesJob.Services, noService, noCredentialsJobBuilderhas no strategy/service methodsAddService(...)+ strategy config on the existing buildersScope — components to create
1. Models (
ADotNet/Models/Pipelines/GithubPipelines/DotNets/)Service— a service container definition.Credentials— registry credentials for a service/container image.Strategyto addfail-fast,max-parallel, and matrixinclude/exclude.Matrixtype to represent axis variables +include+exclude.ServicestoJobasDictionary<string, Service>(service id → definition).2. Builders (
ADotNet/Clients/Builders/)Extend the existing
GitHubPipelineBuilder/JobBuilderflow only — no new builder types(no
ServiceBuilder). Service and strategy configuration is added to the current builders:JobBuilder.AddService(string id, Service service)— attach a service container to the job(the caller constructs the
Servicemodel; add convenience overloads if helpful).JobBuilderstrategy helpers — e.g.WithMatrix(...),AddMatrixInclude(...),WithFailFast(bool),WithMaxParallel(int).3. Tests (
AdoNet.Tests.Unit/)GitHubPipelineBuilder/JobBuilderadditions (service + strategy methods).GitHubPipelineBuildertest proving a full matrix + services workflow serializesto the expected YAML (see
AdoNet.Tests.Unit/Clients/Builders/).Full GitHub surface (must be represented — not limited to the example)
jobs.<job_id>.strategymatrix— arbitrary axis variables:key: [values]matrix.include— list of maps (combinations to add / extend, may add keys not in the axes)matrix.exclude— list of maps (combinations to remove)fail-fast— boolean (GitHub default istrue)max-parallel— integerjobs.<job_id>.services.<service_id>(same schema asjobs.<job_id>.container)image— stringcredentials—{ username, password }env— mapports— list of stringsvolumes— list of strings ← missing from the reference example; still requiredoptions— stringReference component examples
These are illustrative of the shape/conventions expected (match existing
YamlMemberordering andOmitDefaultsusage). Extend as needed to reach full GitHub coverage.Example builder usage (the API we want)
Design considerations / open questions
fail-fastdefault istrue. The meaningful override isfalse. Usebool?(nullable) so anunset value is omitted and an explicit
falseis emitted — a non-nullablebool+OmitDefaultswould silently drop
false.of
include/exclude. YamlDotNet will not flatten a nested dictionary property automatically —a custom representation (e.g. build a single
Dictionary<string, object>where values are eitherList<string>for axes orList<Dictionary<string,string>>for include/exclude) or a customconverter is likely needed.
Strategy.MatrixisDictionary<string, List<string>>,which is public API. Changing its type is a breaking change — decide between (a) evolving
Strategyadditively while preserving the current property, or (b) a versioned successor consistent with the
repo's
V2/V3component pattern.container. DesignServiceso it can be reused for a future job-levelcontainercomponent (identical GitHub schema).Acceptance criteria
ServiceandCredentialsmodels created, covering the full GitHubservices.<id>schema(
image,credentials,env,ports,volumes,options).Strategysupportsfail-fast,max-parallel, and matrixinclude/exclude(in addition to axes).Jobexposes aservicesmap that serializes asservice id -> definition.GitHubPipelineBuilder/JobBuilderextended with methods to add services and configure the strategy — no new builder types.OmitDefaults), consistent with existing models.GitHubPipelineBuildertest that reproduces the matrix + services workflow above.Out of scope