Skip to content

IPublish multi-target in order to allow us to publish both GH and Nuget.org at the same time (plus gating) - #342

Merged
ChrisonSimtian merged 8 commits into
mainfrom
promote/multichannel-publish-to-main
Jun 14, 2026
Merged

IPublish multi-target in order to allow us to publish both GH and Nuget.org at the same time (plus gating)#342
ChrisonSimtian merged 8 commits into
mainfrom
promote/multichannel-publish-to-main

Conversation

@ChrisonSimtian

@ChrisonSimtianChrisonSimtian commented May 31, 2026

Copy link
Copy Markdown
Collaborator

Promotes #333 from experimentalmain (the -preview trunk) for human review ahead of becoming an RC feature. Curated cherry-pick of the feature commits (#339 + #340) — deliberately not a branch merge, so main's version.json stays -preview (experimental's -alpha identity is left behind).

What's promoted

  • PublishTarget + pure PublishPackageRouter (10 unit tests, Fallout.Components.Tests)
  • IPublish[Experimental("FALLOUT001")]PublishTargets + --publish-to — fans one Pack across feeds
  • Build.cs channels: github-packages (all, incl. Nuke.*) + nuget.org (Fallout.* only)
  • experimental.yml / preview.yml now dogfood dotnet fallout Publish instead of hand-rolled dotnet nuget push

Why it's safe to promote

  • Non-breaking: purely additive. The new surface is [Experimental("FALLOUT001")]-gated, and the legacy single-feed members are retained.
  • Validated on experimental: full Test+Pack green, and the post-merge experimental publish ran for real — dotnet fallout Publish --publish-to github-packages published -alpha packages successfully (the token-env fixfix(ci): publish token env var GitHubToken → GITHUB_TOKEN (#333) #340 came out of that live run).

Reviewer notes

Part of epic #332. Issue #333 stays open until this merges to main.

🤖 Generated with Claude Code

@ChrisonSimtianChrisonSimtian added the target/vCurrent Targets the current version label May 31, 2026
@ChrisonSimtian
ChrisonSimtian requested a review from a team as a code ownerMay 31, 2026 11:39
@ChrisonSimtianChrisonSimtian added channel/preview ready-for-review Complete; awaiting human review + merge. labels May 31, 2026
@ChrisonSimtian
ChrisonSimtianforce-pushed the promote/multichannel-publish-to-main branch from 3e5fb74 to 906828cCompareJune 9, 2026 08:29

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Promotes the experimental multi-channel publishing feature onto main by introducing routable publish targets (PublishTarget + PublishPackageRouter), extending IPublish with an [Experimental("FALLOUT001")] multi-target publish surface, and dogfooding it in the preview/experimental GitHub Actions workflows.

Changes:

  • Add PublishTarget + PublishPackageRouter routing (glob include/exclude, skip-duplicate) with a new Fallout.Components.Tests project covering the routing behavior.
  • Extend IPublish with [Experimental("FALLOUT001")] PublishTargets and --publish-to, and update build/Build.cs to define github-packages and nuget.org channels with package-ID routing.
  • Update workflows/docs to use the new GitHub Packages feed URL (Fallout-build) and switch preview/experimental lanes to dotnet fallout Publish.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
tests/Fallout.SourceGenerators.Tests/StronglyTypedSolutionGeneratorTest.Test#Solution.g.verified.csUpdates verified generator output to include the new Fallout.Components.Tests project.
tests/Fallout.Components.Tests/PublishPackageRouterTests.csAdds unit tests for glob matching and include/exclude routing behavior.
tests/Fallout.Components.Tests/Fallout.Components.Tests.csprojIntroduces the new test project for Fallout.Components.
src/Shims/Nuke.Components/README.mdUpdates GitHub Packages feed URL for shim consumption.
src/Shims/Nuke.Common/README.mdUpdates GitHub Packages feed URL references and examples.
src/Shims/Nuke.Build/README.mdUpdates GitHub Packages feed URL for shim consumption.
src/Fallout.Components/PublishTarget.csAdds the publish target model and pure routing helper used by IPublish.
src/Fallout.Components/IPublish.csImplements experimental multi-target publish selection and per-target push behavior.
fallout.slnxAdds the new Fallout.Components.Tests project to the solution.
docs/migration/from-nuke.mdUpdates migration documentation to the new GitHub Packages feed URL.
docs/experimental-apis.mdRegisters FALLOUT001 and documents the experimental surface.
docs/agents/release-and-versioning.mdUpdates release/publish documentation to the new GitHub Packages feed URL.
CHANGELOG.mdUpdates the shim feed URL reference in historical notes.
build/Build.csWires real publish channels via IPublish.PublishTargets and relaxes prior publish gating.
.github/workflows/release.ymlUpdates the GitHub Packages feed URL used for shim pushes.
.github/workflows/preview.ymlSwitches preview publishing to dotnet fallout Publish --publish-to github-packages and fixes token env usage.
.github/workflows/experimental.ymlSwitches experimental publishing to dotnet fallout Publish --publish-to github-packages and fixes token env usage.
.github/CODEOWNERSUpdates code ownership to the @Fallout-build/maintainers team for src/ and tests/.

Comment threadsrc/Fallout.Components/IPublish.cs
Comment threadsrc/Fallout.Components/PublishTarget.cs Outdated
Comment threadsrc/Fallout.Components/IPublish.cs
@ChrisonSimtianChrisonSimtian self-assigned this Jun 14, 2026
ChrisonSimtianand others added 7 commits June 14, 2026 13:12
…he lanes (#333) (#339)
* feat(publish): multi-channel, package-ID-aware publishing surface (#333, FALLOUT001)
IPublish gains [Experimental("FALLOUT001")] PublishTargets + a --publish-to selector;
Publish now routes one Pack output across multiple feeds via the pure, unit-tested
PublishPackageRouter (glob include/exclude by package name). Existing single-source
members stay as a back-compat default target.
Build.cs wires the two real channels: github-packages (every package incl Nuke.*,
keyed by the GitHub token) and nuget.org (Fallout.* only, never Nuke.*, keyed by
NUGET_API_KEY) — replacing the legacy single-feed push.
- src/Fallout.Components/PublishTarget.cs — PublishTarget record + PublishPackageRouter
- tests/Fallout.Components.Tests — 10 router tests (added to fallout.slnx)
- docs/experimental-apis.md — FALLOUT001 registered
Framework compiles clean (0 errors); router tests green. Workflow rewire to
`dotnet fallout Publish --publish-to …` follows once experimental is synced with main.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* ci(publish): dogfood `dotnet fallout Publish` on the alpha/preview lanes (#333)
experimental.yml and preview.yml now publish via `dotnet fallout Publish --publish-to
github-packages` instead of a hand-rolled `dotnet nuget push` loop. Publish depends on
Test + Pack, so one invocation runs Restore → Compile → Test → Pack → Publish as NUKE
stages; package routing (Fallout.* + Nuke.* → GitHub Packages) lives in Build.cs
IPublish.PublishTargets. The GitHub token is passed via the GitHubToken env.
Also restore IPublish.PackagePushSettings + PushSettingsBase (kept for back-compat) so the
multi-channel reshape stays additive — the new PublishTargets/PublishTo surface is the only
opt-in change, behind [Experimental("FALLOUT001")].
release.yml's publish jobs still use raw nuget push (they're coupled to the artifact
handoff + nuget-org approval gate) — dogfooding those is folded into #336.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(publish): make PublishTarget a sealed class so the shim generator skips it
CI caught CS0509: the TransitionShimGenerator tried to derive a Nuke.Components
shim from the sealed *record* PublishTarget. Sealed classes are skipped by design
(SHIM001), but the sealed-record shape slipped past that guard. PublishTarget is a
new type with no pre-rename consumers, so skipping its shim is correct; switching
record→sealed class hits the documented skip path. We don't use record equality/`with`.
Verified: Nuke.Components builds 0 errors (SHIM001 warning only).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(generators): accept solution-generator snapshot for new Fallout.Components.Tests
Adding tests/Fallout.Components.Tests to fallout.slnx makes the StronglyTypedSolution
generator emit a Fallout_Components_Tests accessor; update the Verify snapshot to match
(one added line — the new project's strongly-typed Solution property).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… (#340)
The dogfood `dotnet fallout Publish` run failed with "Publish target 'github-packages'
has no API key". The github-packages target resolves its key via
From<ICreateGitHubRelease>().GitHubToken → GitHubActions.Token, which reads the
GITHUB_TOKEN env var (EnvironmentInfo.GetVariable("GITHUB_TOKEN")). The lane workflows
set `GitHubToken` instead, which didn't match (ICreateGitHubRelease is also
[ParameterPrefix]-ed, so the unprefixed name wouldn't bind anyway). Set GITHUB_TOKEN.
Caught by letting the post-merge experimental publish actually run.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This promotion branch was cherry-picked before the repo transfer, so it still
carried the old ChrisonSimtian GitHub Packages feed URL + CODEOWNERS. Align it
with the post-transfer main/experimental so merging it doesn't re-introduce the
dead feed: feed → Fallout-build, CODEOWNERS → @Fallout-build/maintainers.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot Autofix (86aa4b6) removed `using System.Diagnostics.CodeAnalysis;`
as apparently-unused, but IPublish still applies [Experimental("FALLOUT001")]
on PublishTargets/PublishTo — so the build broke with CS0246
(ExperimentalAttribute could not be found) on the PR validation lanes.
Re-add the using; framework compiles clean, router tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ChrisonSimtian
ChrisonSimtianforce-pushed the promote/multichannel-publish-to-main branch from db43cf9 to 7547fc7CompareJune 14, 2026 01:12
Restore a defense-in-depth guard on the Fallout build's Publish target and
fail fast on misconfigured publish targets.
- Build.cs: require Host is GitHubActions on Publish. GitHubToken binds from
the GITHUB_TOKEN env var, which developers commonly export, so without a
guard a stray local `dotnet fallout Publish` (no --publish-to selects all
targets) would push to GitHub Packages. The CI guard blocks local pushes
while still allowing every CI lane (experimental/preview/release).
- IPublish.Publish: hoist the per-target API-key check out of the push loop
into the pre-flight validation block. A missing key is a config error
knowable before any push, so we now fail fast instead of pushing some feeds
and breaking half-way. Per-push failures stay independent (PushCompleteOnFailure).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ChrisonSimtianChrisonSimtian changed the title Promote: multi-channel publishing (#333) — experimental → main (preview/RC candidate)IPublish multi-target in order to allow us to publish both GH and Nuget.org at the same time (plus gating)Jun 14, 2026
@ChrisonSimtian
ChrisonSimtian merged commit e6479f7 into mainJun 14, 2026
2 checks passed
@ChrisonSimtian
ChrisonSimtian deleted the promote/multichannel-publish-to-main branch June 14, 2026 01:59
ChrisonSimtian added a commit that referenced this pull request Jun 14, 2026
## Problem
The post-merge **preview CD on `main`** (from #342) went red. The target
summary tells the real story — the feature works, a *different* target
failed:
| Target | Result |
|---|---|
| Test | ✅ Passed: 470, Skipped: 7 |
| Pack | ✅ Packages: 22 |
| **Publish** | ✅ **0:07 — pushed 22 packages to GitHub Packages** |
| CreateGitHubRelease | ❌ `NotFoundException: Not Found` |
So `dotnet fallout Publish --publish-to github-packages` (the #333
dogfooding) did exactly its job. The job failed on `CreateGitHubRelease`
getting dragged into the run.
## Root cause
`ICreateGitHubRelease.CreateGitHubRelease` is `.TriggeredBy<IPublish>()`
and was gated only on `.OnlyWhenStatic(() =>
GitRepository.IsOnMainBranch())`.
Before #333, `Publish` ran **only in the release workflow** (its old
`.Requires` gated on `Workflow == ReleaseWorkflow`). #333 replaced that
with `.Requires(Host is GitHubActions)` so the preview/experimental
lanes could dogfood `Publish`. Because **preview pushes to `main`**, the
`IsOnMainBranch()` gate now passes and a GitHub Release is attempted on
every preview push. (Experimental is unaffected — not on `main`, so the
`OnlyWhen` skips it.)
GitHub Releases are **production-only** in the channel model.
`release.yml` hand-rolls them via `gh release create` (the
`publish-github-releases` job) and doesn't invoke this C# target at all.
## Fix
Gate `CreateGitHubRelease` to the release workflow
(`GitHubActions?.Workflow == ReleaseWorkflow`) instead of just
`IsOnMainBranch()`, so it stays dormant on preview/experimental
publishes.
## Validation
`dotnet build build/_build.csproj` clean. Merging this re-triggers the
preview lane on `main`, which should now go green (Publish succeeds,
CreateGitHubRelease skipped).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-reviewComplete; awaiting human review + merge.target/vCurrentTargets the current version

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ChrisonSimtian