Skip to content
Closed
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
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- **Adopted calendar versioning (`YYYY.MINOR.PATCH`) + dual-pace channel model; retired the v11 numbering** ([ADR-0004](docs/adr/0004-calendar-versioning-and-dual-pace-channels.md)). Fallout now ships on calendar versions (`2026.0.0`, `2026.1.0`, …) — mechanically valid SemVer with the major equal to the calendar year. **Breaking changes are batched to the yearly major cut**; mid-year stable releases (`release/YYYY`) are strictly non-breaking. `main` becomes the published **edge** channel (date-stamped prereleases to GitHub Packages); the slow/stable track lives on `release/YYYY`. Opt-in unstable APIs are marked `[Experimental("FALLOUT0xx")]`.
- **Migration / impact**: the `11.0.x` packages never shipped a clean stable release (all unlisted), so this strands no stable consumers. The headline content previously slated for "v11" now ships as **`2026.0.0`**. Any tooling pinned to a `[11.0,12.0)`-style range should retarget the `2026.x` line.
- **Legacy unaffected**: the `release/v10` line stays on semver `10.x` and continues to receive security/critical fixes — v10 consumers do nothing.
- **Renamed public type `MSBuildSettings` → `MsBuildSettings`** for casing consistency with the rest of the API surface (PascalCase acronym: `MsBuild`, not `MSBuild`). The MSBuild tool wrapper's settings type, its extension methods (`Fallout.Common.Tools.MSBuild.MsBuildSettingsExtensions`, `Fallout.Common.CI.TeamCity.MSBuildSettingsExtensions`), and `MSBuildTasks` all reference the new name.
- **Migration / impact**: replace `MSBuildSettings` with `MsBuildSettings` in build code (e.g. `MSBuild(_ => _.Set…())` lambdas are unaffected — they infer the settings type; only explicit `MSBuildSettings`-typed locals/fields/configurators need updating). The `DotNetMSBuildSettings` type (the `dotnet msbuild` wrapper) is unrelated and **not** renamed.
- **No shim**: this is a hard rename with no `[Obsolete]` alias — it rides `experimental` and is batched to the major cut rather than landing mid-year.
- **Inlined `vs-solutionpersistence` parser + renamed `Fallout.SolutionModel` → `Fallout.Solution`; namespace `Fallout.Common.ProjectModel` → `Fallout.Solutions`** (closes #248). The vendored Microsoft fork (`vendor/vs-solutionpersistence/`, submodule, fork-of-fork-of-Microsoft) is gone — sources inlined into a new `Fallout.Persistence.Solution` project under `src/Persistence/`. The facade was renamed and rehoused alongside it (`src/Persistence/Fallout.Solution/`), with the long-standing rebrand-era namespace mismatch (`Fallout.Common.ProjectModel`) fixed to match the assembly name (`Fallout.Solutions`, plural per BCL convention to avoid `Fallout.Solution.Solution` awkwardness).
- **Package IDs**: `Fallout.SolutionModel` → `Fallout.Solution`, `Fallout.VisualStudio.SolutionPersistence` → `Fallout.Persistence.Solution`. Consumers that explicitly referenced either need to update their `PackageReference`/`ProjectReference`.
- **Namespaces**: `Fallout.Common.ProjectModel` → `Fallout.Solutions`; `Microsoft.VisualStudio.SolutionPersistence.{Model,Serializer,Utilities,...}` → `Fallout.Persistence.Solution.{Model,Serializer,Utilities,...}`. Replace `using` statements accordingly. The `Nuke.Common.ProjectModel.*` transition-shim path is preserved (`ShimMarker.cs` now mirrors both `Fallout.Common.*` → `Nuke.Common.*` and `Fallout.Solutions.*` → `Nuke.Common.ProjectModel.*`), so NUKE-era consumer code using `using Nuke.Common.ProjectModel; [Solution] readonly Solution Solution;` keeps compiling.
Expand Down Expand Up @@ -123,7 +126,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
Loading
Loading