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

@ChrisonSimtian ChrisonSimtian 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 fix fix(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

@ChrisonSimtian ChrisonSimtian added the target/vCurrent Targets the current version label May 31, 2026
@ChrisonSimtian
ChrisonSimtian requested a review from a team as a code owner May 31, 2026 11:39
@ChrisonSimtian ChrisonSimtian added channel/preview Preview lane: main -> GitHub Packages -preview prereleases (ADR-0004). ready-for-review Complete; awaiting human review + merge. labels May 31, 2026
@ChrisonSimtian
ChrisonSimtian requested a review from Copilot June 9, 2026 08:25
@ChrisonSimtian
ChrisonSimtian force-pushed the promote/multichannel-publish-to-main branch from 3e5fb74 to 906828c Compare June 9, 2026 08:29

Copilot AI 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
File Description
tests/Fallout.SourceGenerators.Tests/StronglyTypedSolutionGeneratorTest.Test#Solution.g.verified.cs Updates verified generator output to include the new Fallout.Components.Tests project.
tests/Fallout.Components.Tests/PublishPackageRouterTests.cs Adds unit tests for glob matching and include/exclude routing behavior.
tests/Fallout.Components.Tests/Fallout.Components.Tests.csproj Introduces the new test project for Fallout.Components.
src/Shims/Nuke.Components/README.md Updates GitHub Packages feed URL for shim consumption.
src/Shims/Nuke.Common/README.md Updates GitHub Packages feed URL references and examples.
src/Shims/Nuke.Build/README.md Updates GitHub Packages feed URL for shim consumption.
src/Fallout.Components/PublishTarget.cs Adds the publish target model and pure routing helper used by IPublish.
src/Fallout.Components/IPublish.cs Implements experimental multi-target publish selection and per-target push behavior.
fallout.slnx Adds the new Fallout.Components.Tests project to the solution.
docs/migration/from-nuke.md Updates migration documentation to the new GitHub Packages feed URL.
docs/experimental-apis.md Registers FALLOUT001 and documents the experimental surface.
docs/agents/release-and-versioning.md Updates release/publish documentation to the new GitHub Packages feed URL.
CHANGELOG.md Updates the shim feed URL reference in historical notes.
build/Build.cs Wires real publish channels via IPublish.PublishTargets and relaxes prior publish gating.
.github/workflows/release.yml Updates the GitHub Packages feed URL used for shim pushes.
.github/workflows/preview.yml Switches preview publishing to dotnet fallout Publish --publish-to github-packages and fixes token env usage.
.github/workflows/experimental.yml Switches experimental publishing to dotnet fallout Publish --publish-to github-packages and fixes token env usage.
.github/CODEOWNERS Updates code ownership to the @Fallout-build/maintainers team for src/ and tests/.

Comment thread src/Fallout.Components/IPublish.cs
Comment thread src/Fallout.Components/PublishTarget.cs Outdated
Comment thread src/Fallout.Components/IPublish.cs
@ChrisonSimtian ChrisonSimtian self-assigned this Jun 14, 2026
ChrisonSimtian and 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
ChrisonSimtian force-pushed the promote/multichannel-publish-to-main branch from db43cf9 to 7547fc7 Compare June 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>
@ChrisonSimtian ChrisonSimtian 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 main Jun 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 free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel/preview Preview lane: main -> GitHub Packages -preview prereleases (ADR-0004). ready-for-review Complete; awaiting human review + merge. target/vCurrent Targets the current version

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants