Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
# changelogs, etc.) have no code owner and are gated only by the required CI
# status check.

/src/** @ChrisonSimtian
/tests/** @ChrisonSimtian
/src/** @Fallout-build/maintainers
/tests/** @Fallout-build/maintainers
36 changes: 17 additions & 19 deletions .github/workflows/experimental.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ on:
- '.assets/**'
- '**/*.md'

# Cancel a superseded alpha build when a newer commit lands (#322). Never on release.yml.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

Expand All @@ -44,35 +49,28 @@ jobs:
- uses: actions/checkout@v6
with:
fetch-depth: 0 # Nerdbank.GitVersioning needs full history
submodules: recursive
- name: 'Cache: .fallout/temp, ~/.nuget/packages'
uses: actions/cache@v4
with:
path: |
.fallout/temp
~/.nuget/packages
key: ${{ runner.os }}-experimental-${{ hashFiles('**/global.json', '**/*.csproj', '**/Directory.Packages.props', 'version.json') }}
restore-keys: |
${{ runner.os }}-experimental-
- name: 'Setup: .NET SDK'
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: 'Restore: dotnet tools'
run: dotnet tool restore
- name: 'Run: Pack'
run: dotnet fallout Pack
- name: 'Push: all *.nupkg to GitHub Packages (alpha)'
run: |
set -euo pipefail
shopt -s nullglob
packages=(output/packages/*.nupkg)
if [ ${#packages[@]} -eq 0 ]; then
echo "::error::No packages found — nothing to publish to the experimental channel."
exit 1
fi
for pkg in "${packages[@]}"; do
echo "Pushing $pkg to GitHub Packages (alpha)..."
dotnet nuget push "$pkg" \
--source "https://nuget.pkg.github.com/ChrisonSimtian/index.json" \
--api-key "${{ secrets.GITHUB_TOKEN }}" \
--skip-duplicate
done
# Test + Pack + push alpha → GitHub Packages, all through our own framework (#333) —
# dogfooding `dotnet fallout Publish` instead of a hand-rolled `dotnet nuget push`.
# `Publish` depends on Test + Pack, so NUKE runs Restore → Compile → Test → Pack →
# Publish as discrete internal stages and fails at the breaking stage; if Test fails
# the job stops before any push. Which packages go where (Fallout.* + Nuke.* → GitHub
# Packages) is decided by Build.cs IPublish.PublishTargets, not here.
- name: 'Publish: alpha → GitHub Packages'
run: dotnet fallout Publish --publish-to github-packages
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
14 changes: 11 additions & 3 deletions .github/workflows/macos-latest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,20 @@ name: macos-latest

on:
push:
tags:
- 'v*'
pull_request:
branches:
- experimental
- main
- 'release/*'
- 'support/*'
paths-ignore:
- 'docs/**'
- '.assets/**'
- '**/*.md'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
macos-latest:
Expand All @@ -31,7 +40,6 @@ jobs:
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
fetch-depth: 0
- name: 'Cache: .fallout/temp, ~/.nuget/packages'
uses: actions/cache@v4
Expand Down
36 changes: 17 additions & 19 deletions .github/workflows/preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ on:
- '.assets/**'
- '**/*.md'

# Cancel a superseded preview build when a newer commit lands (#322). Never on release.yml.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

Expand All @@ -44,35 +49,28 @@ jobs:
- uses: actions/checkout@v6
with:
fetch-depth: 0 # Nerdbank.GitVersioning needs full history
submodules: recursive
- name: 'Cache: .fallout/temp, ~/.nuget/packages'
uses: actions/cache@v4
with:
path: |
.fallout/temp
~/.nuget/packages
key: ${{ runner.os }}-preview-${{ hashFiles('**/global.json', '**/*.csproj', '**/Directory.Packages.props', 'version.json') }}
restore-keys: |
${{ runner.os }}-preview-
- name: 'Setup: .NET SDK'
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: 'Restore: dotnet tools'
run: dotnet tool restore
- name: 'Run: Pack'
run: dotnet fallout Pack
- name: 'Push: all *.nupkg to GitHub Packages (preview)'
run: |
set -euo pipefail
shopt -s nullglob
packages=(output/packages/*.nupkg)
if [ ${#packages[@]} -eq 0 ]; then
echo "::error::No packages found — nothing to publish to the preview channel."
exit 1
fi
for pkg in "${packages[@]}"; do
echo "Pushing $pkg to GitHub Packages (preview)..."
dotnet nuget push "$pkg" \
--source "https://nuget.pkg.github.com/ChrisonSimtian/index.json" \
--api-key "${{ secrets.GITHUB_TOKEN }}" \
--skip-duplicate
done
# Test + Pack + push preview → GitHub Packages, all through our own framework (#333) —
# dogfooding `dotnet fallout Publish` instead of a hand-rolled `dotnet nuget push`.
# `Publish` depends on Test + Pack, so NUKE runs Restore → Compile → Test → Pack →
# Publish as discrete internal stages and fails at the breaking stage; if Test fails
# the job stops before any push. Which packages go where (Fallout.* + Nuke.* → GitHub
# Packages) is decided by Build.cs IPublish.PublishTargets, not here.
- name: 'Publish: preview → GitHub Packages'
run: dotnet fallout Publish --publish-to github-packages
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5 changes: 3 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,15 @@ jobs:
with:
ref: ${{ inputs.tag || github.ref }}
fetch-depth: 0 # Nerdbank.GitVersioning needs full history
submodules: recursive # vendor/vs-solutionpersistence
- name: 'Cache: .fallout/temp, ~/.nuget/packages'
uses: actions/cache@v4
with:
path: |
.fallout/temp
~/.nuget/packages
key: ${{ runner.os }}-release-${{ hashFiles('**/global.json', '**/*.csproj', '**/Directory.Packages.props', 'version.json') }}
restore-keys: |
${{ runner.os }}-release-
- name: 'Setup: .NET SDK'
uses: actions/setup-dotnet@v4
with:
Expand Down Expand Up @@ -198,7 +199,7 @@ jobs:
for pkg in "${packages[@]}"; do
echo "Pushing $pkg to GitHub Packages..."
dotnet nuget push "$pkg" \
--source "https://nuget.pkg.github.com/ChrisonSimtian/index.json" \
--source "https://nuget.pkg.github.com/Fallout-build/index.json" \
--api-key "${{ secrets.GITHUB_TOKEN }}" \
--skip-duplicate
done
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/ubuntu-latest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,17 @@ on:
- '.assets/**'
- '**/*.md'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
ubuntu-latest:
name: ubuntu-latest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
fetch-depth: 0
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
ref: ${{ github.head_ref }}
Expand Down
14 changes: 11 additions & 3 deletions .github/workflows/windows-latest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,20 @@ name: windows-latest

on:
push:
tags:
- 'v*'
pull_request:
branches:
- experimental
- main
- 'release/*'
- 'support/*'
paths-ignore:
- 'docs/**'
- '.assets/**'
- '**/*.md'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
windows-latest:
Expand All @@ -31,7 +40,6 @@ jobs:
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
fetch-depth: 0
- name: 'Cache: .fallout/temp, ~/.nuget/packages'
uses: actions/cache@v4
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ The NUKE → Fallout hard fork. Originally NUKE by [@matkoch](https://github.com
### Backwards-compat: Nuke.* transition shims
- **`Nuke.Common` MVP shim package** (#70): thin wrapper assembly in the `Nuke.*` namespace whose types inherit from the corresponding `Fallout.*` types — lets pre-rename consumers compile against the new packages without source changes. Lives at `src/Shims/Nuke.Common/`.
- **`TransitionShimGenerator` source generator** (#69): emits shim type wrappers per-target, covering the Nuke.Common "Easy tier" surface (plain types, interfaces, enums) and static-class method delegation. Hard-tier types (sealed structs, delegates, etc.) raise `SHIM001` warnings with a pointer to `fallout-migrate`.
- **Shim packages publish to GitHub Packages** (#47): `Nuke.*` package IDs belong to matkoch on nuget.org, so the transition shim feed lives at GH Packages (`https://nuget.pkg.github.com/ChrisonSimtian/index.json`). Production-build feed is nuget.org with `Fallout.*` only.
- **Shim packages publish to GitHub Packages** (#47): `Nuke.*` package IDs belong to matkoch on nuget.org, so the transition shim feed lives at GH Packages (`https://nuget.pkg.github.com/Fallout-build/index.json`). Production-build feed is nuget.org with `Fallout.*` only.

### Vendored fork of `Microsoft.VisualStudio.SolutionPersistence`
- **Replaced `matkoch.Microsoft.VisualStudio.SolutionPersistence` with a vendored fork** (#86). The upstream Microsoft package only ships `net472` + `net8.0`; our source generators need `netstandard2.0`. Matt's fork had the netstandard2.0 patches — we forked his repo at [`ChrisonSimtian/vs-solutionpersistence`](https://github.com/ChrisonSimtian/vs-solutionpersistence) (preserves the MIT license + upstream Microsoft history + attribution chain). Sources are a submodule at `vendor/vs-solutionpersistence/`; wrapper csproj at `src/Fallout.VisualStudio.SolutionPersistence/` compiles them with the TFMs we need. Assembly name stays `Microsoft.VisualStudio.SolutionPersistence` so type identity is preserved. (Note: in 10.2 the wrapper packed as `IsPackable=false` and caused the restore bug fixed in 10.3.0 above — known issue, fix-forward.)
Expand Down
44 changes: 29 additions & 15 deletions build/Build.CI.GitHubActions.cs
Original file line number Diff line number Diff line change
@@ -1,37 +1,51 @@
using Fallout.Common.CI.GitHubActions;
using Fallout.Components;

// macOS and Windows runs are reserved for post-merge validation on the
// long-lived branches (experimental, main, release/YYYY, support/*). PRs and
// feature-branch pushes get Linux-only for fast, cheap feedback. Cross-platform
// regressions on those branches surface as a red commit — same fail-fast model.
// Cross-platform (macOS/Windows) full Test+Pack is gated to RELEASE INTENT
// (#318/#326): it runs only on a PR into a production branch (release/YYYY,
// support/*) and on a release tag push (v*) — never on routine pushes to
// main/experimental, never on a per-merge basis. On main/experimental "we've
// got our edge": the ubuntu-latest PR gate + the alpha/preview pipelines.
// (workflow_dispatch as a manual cross-platform trigger isn't emitted here —
// the generator only writes workflow_dispatch when it has inputs; GitHub's
// built-in run re-run covers the on-demand case.)
//
// concurrency cancel-in-progress (#322): superseded runs are cancelled rather
// than stacked. Never applied to release.yml (a publish must not be cancelled).
[GitHubActions(
"macos-latest",
GitHubActionsImage.MacOsLatest,
FetchDepth = 0,
Submodules = GitHubActionsSubmodules.Recursive,
OnPushBranches = new[] { ExperimentalBranch, MainBranch, ReleaseBranchPattern, SupportBranchPattern },
ConcurrencyGroup = "${{ github.workflow }}-${{ github.ref }}",
ConcurrencyCancelInProgress = true,
OnPushTags = new[] { "v*" },
OnPullRequestBranches = new[] { ReleaseBranchPattern, SupportBranchPattern },
OnPullRequestExcludePaths = new[] { "docs/**", ".assets/**", "**/*.md" },
InvokedTargets = new[] { nameof(ITest.Test), nameof(IPack.Pack) },
PublishArtifacts = false)]
[GitHubActions(
"windows-latest",
GitHubActionsImage.WindowsLatest,
FetchDepth = 0,
Submodules = GitHubActionsSubmodules.Recursive,
OnPushBranches = new[] { ExperimentalBranch, MainBranch, ReleaseBranchPattern, SupportBranchPattern },
ConcurrencyGroup = "${{ github.workflow }}-${{ github.ref }}",
ConcurrencyCancelInProgress = true,
OnPushTags = new[] { "v*" },
OnPullRequestBranches = new[] { ReleaseBranchPattern, SupportBranchPattern },
OnPullRequestExcludePaths = new[] { "docs/**", ".assets/**", "**/*.md" },
InvokedTargets = new[] { nameof(ITest.Test), nameof(IPack.Pack) },
PublishArtifacts = false)]
// pull_request only — same-repo branches would otherwise fire both push and
// pull_request events on every push, double-running the validation.
//
// CheckoutRef = github.head_ref pins checkout to the PR source branch instead of the merge SHA,
// keeping HEAD attached so GitHubTasksTest.GitHubRepositoryFromLocalDirectoryTest (which reads
// .git/HEAD via GitRepository.FromLocalDirectory) resolves a non-null branch.
// The Linux PR gate — the only required status check. pull_request only:
// feature-branch pushes run zero CI until a PR is opened against a long-lived
// branch (#327). CheckoutRef = github.head_ref pins checkout to the PR source
// branch instead of the merge SHA, keeping HEAD attached so
// GitHubTasksTest.GitHubRepositoryFromLocalDirectoryTest (which reads .git/HEAD
// via GitRepository.FromLocalDirectory) resolves a non-null branch.
[GitHubActions(
"ubuntu-latest",
GitHubActionsImage.UbuntuLatest,
FetchDepth = 0,
Submodules = GitHubActionsSubmodules.Recursive,
ConcurrencyGroup = "${{ github.workflow }}-${{ github.ref }}",
ConcurrencyCancelInProgress = true,
CheckoutRef = "${{ github.head_ref }}",
// Trigger for PRs targeting experimental, main, or any release/YYYY / support/*
// branch — all are long-lived and protected; all require the ubuntu-latest check.
Expand Down
50 changes: 30 additions & 20 deletions build/Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,31 +127,41 @@ from framework in project.GetTargetFrameworks()

[Parameter] [Secret] readonly string NuGetApiKey;

// Publishing to nuget.org now that the Fallout.* rename has landed (#54).
// Requires NUGET_API_KEY in repo secrets — see release.yml.
string IPublish.NuGetSource => "https://api.nuget.org/v3/index.json";
string IPublish.NuGetApiKey => NuGetApiKey;

// Two publish channels (FALLOUT001 — see IPublish.PublishTargets). Routing replaces the
// old single-feed push + the hand-rolled `dotnet nuget push` in the workflows (#333):
// - github-packages: EVERY package, incl. the Nuke.* shims — that ID is owned by the
// original NUKE maintainer (#47), so the shims only ever go here. Keyed by the GitHub token.
// - nuget.org: Fallout.* ONLY, never the Nuke.* shims. Keyed by NUGET_API_KEY.
// Select per run from CI with `dotnet fallout Publish --publish-to <name>`. PublishTarget.SkipDuplicate
// (default true) keeps re-runs idempotent if a version already exists on a feed.
#pragma warning disable FALLOUT001 // opting our own build into the experimental multi-channel publish surface
IEnumerable<PublishTarget> IPublish.PublishTargets => new[]
{
new PublishTarget
{
Name = "github-packages",
Source = "https://nuget.pkg.github.com/Fallout-build/index.json",
ApiKey = From<ICreateGitHubRelease>().GitHubToken,
},
new PublishTarget
{
Name = "nuget.org",
Source = "https://api.nuget.org/v3/index.json",
ApiKey = NuGetApiKey,
IncludePackages = new[] { "Fallout.*" },
ExcludePackages = new[] { "Nuke.*" },
},
};
#pragma warning restore FALLOUT001

// The workflows now gate which channel publishes (via --publish-to); no on-branch
// requirement here. Missing keys fail per-target inside Publish, so a stray local
// `dotnet fallout Publish` is safe (no key → clear error, no push).
Target IPublish.Publish => _ => _
.Inherit<IPublish>()
.Consumes(From<IPack>().Pack)
.Requires(() => GitRepository.IsOnMainBranch() && Host is GitHubActions && GitHubActions.Workflow == ReleaseWorkflow)
.WhenSkipped(DependencyBehavior.Execute);

// Filter `Nuke.*` shim packages out of the nuget.org push — that ID is owned by
// the original NUKE maintainer. The shims still build and pack as artifacts; they
// are pushed to GitHub Packages by a follow-up step in .github/workflows/release.yml
// (#47).
IEnumerable<AbsolutePath> IPublish.PushPackageFiles
=> From<IPack>().PackagesDirectory.GlobFiles("*.nupkg")
.Where(x => !x.NameWithoutExtension.StartsWith("Nuke.", StringComparison.OrdinalIgnoreCase));

// `--skip-duplicate` makes nuget push idempotent: if a version is already on the feed,
// skip it instead of erroring. Lets us rerun release.yml safely when a single package
// fails mid-batch without nuking the whole pipeline on retry.
Configure<DotNetNuGetPushSettings> IPublish.PushSettings => _ => _
.EnableSkipDuplicate();

IEnumerable<AbsolutePath> NuGetPackageFiles
=> From<IPack>().PackagesDirectory.GlobFiles("*.nupkg");

Expand Down
Loading
Loading