Skip to content

feat(ci): CI host integration as ports & adapters (ADR-0005)#341

Open
ChrisonSimtian wants to merge 5 commits into
experimentalfrom
feature/ci-ports-and-adapters
Open

feat(ci): CI host integration as ports & adapters (ADR-0005)#341
ChrisonSimtian wants to merge 5 commits into
experimentalfrom
feature/ci-ports-and-adapters

Conversation

@ChrisonSimtian

@ChrisonSimtian ChrisonSimtian commented May 31, 2026

Copy link
Copy Markdown
Collaborator

Adds the runtime-host ports & adapters seam for CI host integration (ADR-0005), validated by a GitHub-adapter spike and a new Forgejo adapter. Additive / non-breaking. Targets experimental.

What

  • Two ports, split by implementor set: IBuildHost (context — branch/commit/is-PR — CI hosts only) and IBuildReporter (warnings/errors/grouping — every host, including local Terminal).
  • Generalized discovery: Host.Default probes an overridable Host.IsActive instead of the magic-string IsRunning{Name} convention. The old convention stays as fallback, so existing hosts are unchanged.
  • Fitness tests enforce the boundary (ports never reference adapters) and the split (Terminal is a reporter, not a context-host).
  • Forgejo adapter — first provider on the new seam: IsActive override (no static), both ports, and config generation by composing the GitHub config model + a shared WorkflowCommands helper rather than inheriting GitHubActions.

Why

Establishes a stable, enforced CI-adapter seam ahead of the public plugin SDK (milestone #7), without breaking consumers. Full rationale in ADR-0005.

Validation

  • Clean build; Build.Tests 107, Common.Tests 46 green.
  • Generated .github workflows byte-identical (config path untouched).
  • No behaviour change to existing hosts.

Follow-ups (in the spike doc)

  • Forgejo detection is a naive FORGEJO_ACTIONS guess — confirm against a live instance.
  • Full Forgejo config parity needs the GitHub model-builder extracted from file placement.
  • Dedup WorkflowCommands onto GitHubActions (deferred to protect that adapter's byte-identical output).

Docs: docs/adr/0005-ci-host-integration-ports-and-adapters.md, docs/spikes/0001-ci-ports-and-adapters.md.

🤖 Generated with Claude Code

@ChrisonSimtian ChrisonSimtian added the target/2026 Targets the 2026 calendar-version line (current). See ADR-0004. label May 31, 2026
ChrisonSimtian added a commit that referenced this pull request Jun 3, 2026
…ts (onion step 5b)

Move the concrete CI host providers (AppVeyor, AzurePipelines, TeamCity,
GitHubActions, GitLab, TravisCI, Jenkins, Bitrise, Bitbucket, Bamboo,
SpaceAutomation) and their config generators from Fallout.Common.CI.* to
Fallout.Infrastructure.CI.*.

The Application ring uses provider-SPECIFIC capabilities (PublishTestResults,
PushArtifact, SetBuildNumber, UpdateBuildNumber, Token, …), so a generic host
abstraction can't capture them. Instead, per-provider ports in
Fallout.Application.CI — IAppVeyor/IAzurePipelines/ITeamCity/IGitHubActions —
plus a CiHost accessor that casts the detected Host.Instance to the port (null
when not running on that host). No registration needed: Host.Instance is the
existing detection seam, and the providers (subclasses of Host) implement the
ports. Components (ITest/IReportCoverage/ISignPackages/ICreateGitHubRelease) and
version/coverage attributes now call CiHost.X instead of X.Instance, so the
Application ring keeps no dependency on Fallout.Infrastructure.* — the fitness
gate still passes. The two enums the ports expose move to Fallout.Application.CI
as vocabulary. Nuke.Common CI host shims repointed to the new namespace.

(The generic CI host abstraction — ADR-0005 IBuildHost/IBuildReporter, #341 —
stays a separate additive effort.)

Tooling: OnionRewriter rules retargeted for 5b (CI → Infrastructure.CI, enums
overridden to Application.CI). Lesson #13: alias-qualified `global::Ns.Type`
refs aren't rewritten (Left includes `global::`) — hit in the shims, mopped up.

Full suite green; Application-ring fitness gate green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ChrisonSimtian and others added 5 commits June 3, 2026 19:25
Model CI host integration as ports & adapters (hexagonal seam) with an
additive-now / deletions-batched-to-the-year-cut compatibility strategy,
plus the GitHub-adapter-end-to-end spike that validates the runtime-host
port shape.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Additive seam per ADR-0005: IBuildHost supersedes the anemic IBuildServer as
the build's-eye-view runtime-host port (context + reporting). GitHubActions
implements it via explicit interface implementation, leaving the public
surface and generated workflows untouched. Adds an architecture fitness test
asserting the ports layer (Fallout.Build) never references the adapters layer
(Fallout.Common).

Spike work on experimental; LogEventSink rewire deferred (see spike verdict #2).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two ports, justified by differing implementor sets: every Host reports (so
the local Terminal is an IBuildReporter), but only CI hosts carry run context
(so Terminal is not an IBuildHost). IBuildHost rescoped to context (branch/
commit/is-PR); new IBuildReporter (warnings/errors/grouping) implemented by the
Host base via explicit impls over the existing protected-virtual hooks — so
adapters override reporting exactly as before. No behavior change.

Fitness tests pin the split (Terminal: reporter not host; GitHubActions: both).
Corrects spike finding #2 (reporting was already wired in the *.Theming.cs
partials; there was no latent bug). Updates ADR-0005 + spike verdict.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Host.Default now probes an overridable Host.IsActive member instead of
reflecting for the magic-string IsRunning{TypeName} static. The default
IsActive falls back to that legacy convention, so all existing hosts work
unchanged; new adapters override IsActive directly (no static, no name match).
Host ctors are side-effect-free, so construct-then-probe is cheap and the
active host (constructed last) remains Host.Instance.

Covers ADR-0005 #3. Tests exercise both the override and fallback paths.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
First adapter built on the finished ADR-0005 seam, proving it generalizes:
- Runtime host overrides Host.IsActive (no IsRunning{Name} static — first user
  of the #3 detection style) and implements both ports (IBuildHost context via
  GitHub-compatible GITHUB_* vars; IBuildReporter reporting).
- Config generation composes the GitHub config model + a shared WorkflowCommands
  helper for the ::cmd:: dialect, rather than inheriting GitHubActionsAttribute
  (which is blocked anyway by ConfigurationAttributeBase.Build's internal set).
  Common-case scaffold; full parity needs the GH model-builder extracted.
- Detection (FORGEJO_ACTIONS) is a naive guess pending the live instance.

Tests assert both ports, the IsActive detection path, and non-inheritance from
the GitHubActions adapter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ChrisonSimtian ChrisonSimtian force-pushed the feature/ci-ports-and-adapters branch from 9735c5e to 64b1ea9 Compare June 3, 2026 07:25
@ChrisonSimtian ChrisonSimtian requested a review from a team as a code owner June 3, 2026 07:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

target/2026 Targets the 2026 calendar-version line (current). See ADR-0004.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant