Skip to content

Continuous delivery model: IPublishTarget, channels, environments (ADR-0009)#498

Draft
ChrisonSimtian wants to merge 6 commits into
Fallout-build:mainfrom
ChrisonSimtian:rfc/continuous-delivery-model
Draft

Continuous delivery model: IPublishTarget, channels, environments (ADR-0009)#498
ChrisonSimtian wants to merge 6 commits into
Fallout-build:mainfrom
ChrisonSimtian:rfc/continuous-delivery-model

Conversation

@ChrisonSimtian

Copy link
Copy Markdown
Collaborator

Draft / discussion piece. First cut of Fallout's CD domain model — for maintainer review before the provider implementations land. Builds on ADR-0001; settles the DeploymentTarget half of #334 / epic #332.

The model (ADR-0009)

A coherent vocabulary on top of ADR-0001's mechanism:

  • Release — an immutable snapshot (a v* tag), built once.
  • Artifact — what the build produces: packages, assemblies, releasenotes, symbols, source, documentation, homebrew-formula.
  • Target — a distribution endpoint (nuget.org, github-packages, github-releases, homebrew, docs) implementing IPublishTarget.
  • Environment — a promotion stage (DevStagingProduction) that groups targets and carries a gate.
  • Channel — which environments a release is eligible for (preview→Dev,Staging; release→Dev,Staging,Production).
  • Deployment — one (artifact → target) push; tracked + retryable.

Invariant: build once; promote that single immutable artifact through a channel's environments; never promote across channels (a -preview build is never re-versioned into GA). This is why "build once" and "Dev→Staging→Prod" are both true — maturity is fixed at build time; environments only control distribution reach.

Two layers: the domain model is provider-neutral; the GitHub realization maps each target to a GitHub Environment (per-target Deployment records) with a single production env as the promotion gate. Full rationale + mermaid diagram in docs/adr/0009-continuous-delivery-model.md.

Code in this cut (all [Experimental("FALLOUT005")])

  • IPublishTarget — generalizes the NuGet-feed-shaped PublishTarget (which now implements it and owns its own DeployAsync). IPublish.PublishTargetsIEnumerable<IPublishTarget>; Publish builds one Artifact and fans it out.
  • Artifact/ArtifactKind, Channel, DeploymentEnvironment, DeploymentContext.
  • GitHubReleaseTarget — a second implementation (stub; deploy path builds on GitHubReleaseTasks from ADR-0001, tracked by First-class ReleaseChannel / DeploymentTarget / Environment model #334).
  • TransitionShimGenerator now skips [Experimental] types — new opt-in surface has no Nuke.* consumers to bridge, and shimming it leaked the experimental diagnostic into generated code.

Decisions captured

  1. Green-field off main (v10.4 bridge); model is version-scheme-agnostic.
  2. Environment = target-group; GitHub realization = per-target envs + one production gate.
  3. github-packages spans Staging + Production; github-releases is Production (optional pre-release in Staging).
  4. Cross-repo targets (docs, homebrew) start in-pipeline, evolve to downstream-owned via repository_dispatch.

Deferred to refinement passes (weekend work)

  • GitHub provider implementations: GitHubReleaseTasks, GitHubEnvironment sync (ADR-0001 patterns).
  • The reusable publish-{artifact}-{target} workflows + build-once release orchestrator.
  • Homebrew + docs (Docusaurus) targets.
  • Generating the promotion diagram from the model.

Verification

  • dotnet fallout Test Pack → green; all relevant specs pass (incl. new PublishTargetSpecs, all shim specs). The 3 GitRepositoryWorktreeSpecs failures are pre-existing and environment-specific (reproduce on a clean base), unrelated to this change.
  • Existing Verify snapshots unaffected (the generator skip only applies to new experimental types).

ChrisonSimtian and others added 2 commits July 17, 2026 14:55
Complements ADR-0001 (CD mechanism: attributes/tasks/hybrid) with the domain
model our release flow reasons in: release → channel → environment → target →
deployment, and the build-once/promote-within-a-channel invariant. Records the
decisions on environments-as-target-groups, the GitHub realization (per-target
environments + a single production gate), targets spanning environments, and
cross-repo targets. Settles the DeploymentTarget half of Fallout-build#334 / epic Fallout-build#332.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Generalize the NuGet-feed-shaped PublishTarget into an IPublishTarget interface
so a single build fans out to many kinds of destination (feeds, GitHub Releases,
Homebrew, docs) — the DeploymentTarget of Fallout-build#334, per ADR-0009.

- New experimental types (FALLOUT005): IPublishTarget, Artifact/ArtifactKind,
  Channel, DeploymentEnvironment, DeploymentContext, and a GitHubReleaseTarget
  stub (deploy path builds on GitHubReleaseTasks from ADR-0001, tracked by Fallout-build#334).
- PublishTarget now implements IPublishTarget: it is the NuGet-feed provider and
  owns its own DeployAsync (the push logic moved off IPublish.Publish onto the
  target). IPublish.PublishTargets returns IEnumerable<IPublishTarget>; Publish
  builds one immutable artifact and deploys it to each accepting target.
- TransitionShimGenerator now skips [Experimental] types — they are new, opt-in
  surface with no pre-rename Nuke.* consumers to bridge, and shimming them leaked
  the error-by-default experimental diagnostic into generated code.
- Register FALLOUT005 in the experimental-API registry.

First cut for a draft/discussion PR. Deferred to refinement: the GitHub provider
implementations (GitHubReleaseTasks, GitHubEnvironment sync), the reusable
publish workflows, Homebrew/docs targets, and diagram generation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ChrisonSimtian ChrisonSimtian added enhancement New feature or request target/vCurrent Targets the current version labels Jul 17, 2026
- Consolidate the six behavioural partials (CodeGeneration, PublicApi,
  Licenses, Contributors, Stargazers, GlobalSolution) into a single
  Build.Maintenance.cs, and drop the Build.RunTargetInDockerTest.cs demo
  target. The attribute-bearing partials (Build.CI.GitHubActions,
  Build.Terminal) stay separate — class-level attributes can't be merged.
  build/ goes from 10 .cs files to 4.
- Fix .editorconfig end_of_line crlf -> lf so it matches the repo (all LF
  via .gitattributes); crlf made dotnet format rewrite the whole tree and
  unusable. Build files now pass dotnet format cleanly.
- Sort usings, drop a stray private modifier, normalize attribute spacing,
  and replace legacy new string[0] with [].
- Correct conventions.md + CONTRIBUTING.md: they claimed .editorconfig /
  *.DotSettings were removed, but both exist and are actively curated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Packages,

/// <summary>Compiled assemblies (<c>.dll</c>).</summary>
Assemblies,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Assemblies,
Binaries,

to match /bin?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably better to have this as a type, more open ended. But v1 enum is fine for now lets see how it goes

ChrisonSimtian and others added 2 commits July 19, 2026 00:02
Replace the single Build.Maintenance.cs partial with one component interface
per step under build/Steps/, mirroring the migrator's "each unit is its own
type" shape but on the framework's native grain (like IRestore/ICompile):

- IGenerateTools (References, GenerateTools), IGeneratePublicApi,
  IDownloadLicenses, IHandleExternalRepositories, IUpdateContributors,
  IUpdateStargazers.
- Build.cs implements them — its base list is the "wire up the steps" seam.
- Each target stays CLI-invocable and graph-aware: Pack still gains
  DownloadLicenses via DependentFor<IPack>; UpdateContributors inherits
  IHandleExternalRepositories for the external-repo directory.
- UseHttps moves from a readonly [Parameter] field to a [Parameter] property
  (the component idiom); MainBranch stays a const on Build (it feeds a
  [GitHubActions] attribute), so IGenerateTools carries its own ToolsSourceBranch.

No behaviour change: dotnet fallout --help lists every target as before.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Regenerated schema drops the removed RunTargetInDockerImageTest entry so the
build's target list matches reality.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Remove unused members carried over from upstream NUKE: Build.MilestoneTitle,
  and GlobalSolution / ExternalSolutions on IHandleExternalRepositories (no
  references anywhere; they were for a global-solution target this build lacks).
- Delete the commented-out example blocks in _build.csproj (PackAsTool,
  PublishSingleFile, NukeExternalFiles, source-generator scaffolding).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ChrisonSimtian ChrisonSimtian added target/vNext Targets the next calendar-version and removed target/vCurrent Targets the current version labels Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request target/vNext Targets the next calendar-version

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant