diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
new file mode 100644
index 000000000..a8483d332
--- /dev/null
+++ b/.config/dotnet-tools.json
@@ -0,0 +1,12 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "fallout.globaltool": {
+ "version": "10.4.0",
+ "commands": [
+ "fallout"
+ ]
+ }
+ }
+}
diff --git a/.nuke/build.schema.json b/.fallout/build.schema.json
similarity index 88%
rename from .nuke/build.schema.json
rename to .fallout/build.schema.json
index 6c323a9c0..c762f7ff0 100644
--- a/.nuke/build.schema.json
+++ b/.fallout/build.schema.json
@@ -51,7 +51,7 @@
"Quiet"
]
},
- "NukeBuild": {
+ "FalloutBuild": {
"properties": {
"Continue": {
"type": "boolean",
@@ -105,6 +105,13 @@
"Verbosity": {
"description": "Logging verbosity during build execution. Default is 'Normal'",
"$ref": "#/definitions/Verbosity"
+ },
+ "BuildProjectFile": {
+ "type": [
+ "null",
+ "string"
+ ],
+ "description": "Path to the build project (.csproj) relative to the repository root. Defaults to 'build/_build.csproj' when unset. Read by the Fallout global tool's in-tool runner."
}
}
}
@@ -118,15 +125,15 @@
},
"Configuration": {
"type": "string",
- "description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)",
"enum": [
"Debug",
"Release"
- ]
+ ],
+ "description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)"
},
"NuGetApiKey": {
"type": "string",
- "default": "Secrets must be entered via 'nuke :secrets [profile]'"
+ "default": "Secrets must be entered via 'fallout :secrets [profile]'"
},
"NuGetSource": {
"type": "string"
@@ -157,7 +164,7 @@
}
},
{
- "$ref": "#/definitions/NukeBuild"
+ "$ref": "#/definitions/FalloutBuild"
}
]
}
diff --git a/.fallout/parameters.json b/.fallout/parameters.json
new file mode 100644
index 000000000..b1b94afb6
--- /dev/null
+++ b/.fallout/parameters.json
@@ -0,0 +1,5 @@
+{
+ "$schema": "./build.schema.json",
+ "Solution": "Spring.Net.sln",
+ "BuildProjectFile": "build-support/build/_build.csproj"
+}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index f84af230b..b9102f1a3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,6 +27,7 @@ _ReSharper*/
#Project files
[Bb]uild/
+!/build-support/build/
s3-credentials.ps1
TIBCO.EMS.*
@@ -88,5 +89,5 @@ project.lock.json
BenchmarkDotNet.Artifacts*
/artifacts
-/.nuke/temp
+/.fallout/temp
node_modules
\ No newline at end of file
diff --git a/.nuke/parameters.json b/.nuke/parameters.json
deleted file mode 100644
index cd89d7cd9..000000000
--- a/.nuke/parameters.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "$schema": "./build.schema.json",
- "Solution": "Spring.Net.sln"
-}
\ No newline at end of file
diff --git a/AGENTS.md b/AGENTS.md
index 5c21793c5..f0719902c 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -8,7 +8,7 @@ Spring.NET is a port and extension of the Java Spring Framework for .NET: IoC co
## Build and test commands
-Build orchestration is NUKE (`build-support/nuke-build`). Root-level bootstrap scripts install the pinned .NET SDK if missing (`global.json`: 10.0.100, rollForward latestMinor).
+Build orchestration is Fallout (`build-support/build`), the maintained successor to NUKE. Root-level bootstrap scripts install the pinned .NET SDK if missing (`global.json`: 10.0.100, rollForward latestMinor), then run the build through the `fallout` local tool (`dotnet tool restore` + `dotnet fallout`).
```
./build.cmd # Windows (build.sh on Linux/macOS); default target = Compile
@@ -34,7 +34,7 @@ dotnet test test/Spring/Spring.Core.Tests/Spring.Core.Tests.csproj -f net8.0 --f
### Integration tests
-NUKE's `Test` target excludes `*.Integration.Tests` projects (and `Spring.Web.Conversation.NHibernate5.Tests`) by default; they need external infrastructure and are gated behind flags: `--test-full`, `--test-integration-data`, `--test-integration-nms`, `--test-integration-ms-mq`, `--test-integration-ems`. `Spring.Services.Tests` is always excluded. Several test projects are Windows-only (net462: Web, Mvc5, Velocity, Messaging/MSMQ).
+Fallout's `Test` target excludes `*.Integration.Tests` projects (and `Spring.Web.Conversation.NHibernate5.Tests`) by default; they need external infrastructure and are gated behind flags: `--test-full`, `--test-integration-data`, `--test-integration-nms`, `--test-integration-ms-mq`, `--test-integration-ems`. `Spring.Services.Tests` is always excluded. Several test projects are Windows-only (net462: Web, Mvc5, Velocity, Messaging/MSMQ).
- SQL Server-backed tests (`Spring.Data.Integration.Tests`, `Spring.Data.NHibernate5.Integration.Tests`, `Spring.Scheduling.Quartz3.Integration.Tests`): `docker-compose.yml` brings up SQL Server; setup scripts in `build-support/*.sql` and the test projects' `Data/` folders. See README.md "Running tests" for the full recipe.
- TIBCO EMS projects need `TIBCO.EMS.dll` (not in the repo) and are excluded from the solution build; enable with `--build-ems`.
@@ -71,10 +71,10 @@ Key mechanics (defined in `src/Directory.Build.props` and `test/Directory.Build.
## Legacy areas — do not modify
-- NAnt-era build files, superseded by NUKE but still committed: `Spring.build`, `*.include`, `Build-ci.cmd`, `build-release-all.cmd`, `appveyor.yml.old`, most of `build-support/` (exception: `build-support/tools/antlr-2.7.6` is still used by the `Antlr` target).
+- NAnt-era build files, superseded by the Fallout build but still committed: `Spring.build`, `*.include`, `Build-ci.cmd`, `build-release-all.cmd`, `appveyor.yml.old`, most of `build-support/` (exception: `build-support/tools/antlr-2.7.6` is still used by the `Antlr` target).
- `dev-support/`, `templates/` — VS 2008-era templates. `lib/` — checked-in legacy third-party DLLs. `doc/` — DocBook sources + vendored toolchain (CI ignores `doc/**`).
- Orphan test folders not in the solution (reference removed projects): `test/Spring/Spring.Web.Mvc.Tests`, `Spring.Messaging.Ems.Tests`, `Spring.Data.NHibernate.Tests`.
## Website
-`website/` is a Gatsby 5 + React + TypeScript site (package manager: **yarn**). Local dev: `yarn install && yarn start`. The full build is `./build.sh website` (NUKE target; also builds the DocBook reference docs, which require Java on PATH). Deployed to GitHub Pages by `.github/workflows/website.yml` on pushes to `main`.
+`website/` is a Gatsby 5 + React + TypeScript site (package manager: **yarn**). Local dev: `yarn install && yarn start`. The full build is `./build.sh website` (Fallout target; also builds the DocBook reference docs, which require Java on PATH). Deployed to GitHub Pages by `.github/workflows/website.yml` on pushes to `main`.
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 97445e544..0e675d5e3 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -11,6 +11,7 @@
+
@@ -25,7 +26,6 @@
-
@@ -38,6 +38,6 @@
-
+
\ No newline at end of file
diff --git a/Spring.Net.sln b/Spring.Net.sln
index 90d80b2c4..a2538b351 100644
--- a/Spring.Net.sln
+++ b/Spring.Net.sln
@@ -102,7 +102,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spring.Benchmark", "test\Sp
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{9537C677-ADE5-4503-AFD7-3E0C3B0960EB}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "build-support\nuke-build\_build.csproj", "{0D135B50-2B59-44C1-941A-32B5EC798C88}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "build-support\build\_build.csproj", "{0D135B50-2B59-44C1-941A-32B5EC798C88}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{C0BAC5A1-AC38-4D36-BE28-F5A74BD9FECD}"
ProjectSection(SolutionItems) = preProject
diff --git a/build-support/nuke-build/.editorconfig b/build-support/build/.editorconfig
similarity index 100%
rename from build-support/nuke-build/.editorconfig
rename to build-support/build/.editorconfig
diff --git a/build-support/nuke-build/Build.Documentation.cs b/build-support/build/Build.Documentation.cs
similarity index 96%
rename from build-support/nuke-build/Build.Documentation.cs
rename to build-support/build/Build.Documentation.cs
index a905e0f58..19f98fa44 100644
--- a/build-support/nuke-build/Build.Documentation.cs
+++ b/build-support/build/Build.Documentation.cs
@@ -1,6 +1,6 @@
-using Nuke.Common;
-using Nuke.Common.IO;
-using Nuke.Common.Tooling;
+using Fallout.Common;
+using Fallout.Common.IO;
+using Fallout.Common.Tooling;
public partial class Build
{
diff --git a/build-support/nuke-build/Build.GitHubActions.cs b/build-support/build/Build.GitHubActions.cs
similarity index 84%
rename from build-support/nuke-build/Build.GitHubActions.cs
rename to build-support/build/Build.GitHubActions.cs
index f61ff311f..738d8606e 100644
--- a/build-support/nuke-build/Build.GitHubActions.cs
+++ b/build-support/build/Build.GitHubActions.cs
@@ -1,4 +1,4 @@
-using Nuke.Common;
+using Fallout.Common;
public partial class Build
{
diff --git a/build-support/nuke-build/Build.Publish.cs b/build-support/build/Build.Publish.cs
similarity index 88%
rename from build-support/nuke-build/Build.Publish.cs
rename to build-support/build/Build.Publish.cs
index 205568b69..d54e8d95d 100644
--- a/build-support/nuke-build/Build.Publish.cs
+++ b/build-support/build/Build.Publish.cs
@@ -1,9 +1,9 @@
using System.Collections.Generic;
-using Nuke.Common;
-using Nuke.Common.IO;
-using Nuke.Common.Tooling;
-using Nuke.Common.Tools.DotNet;
-using static Nuke.Common.Tools.DotNet.DotNetTasks;
+using Fallout.Common;
+using Fallout.Common.IO;
+using Fallout.Common.Tooling;
+using Fallout.Common.Tools.DotNet;
+using static Fallout.Common.Tools.DotNet.DotNetTasks;
public partial class Build
{
diff --git a/build-support/nuke-build/Build.Test.cs b/build-support/build/Build.Test.cs
similarity index 95%
rename from build-support/nuke-build/Build.Test.cs
rename to build-support/build/Build.Test.cs
index fd1a0f5e4..27dc78a82 100644
--- a/build-support/nuke-build/Build.Test.cs
+++ b/build-support/build/Build.Test.cs
@@ -1,7 +1,7 @@
using System.Linq;
-using Nuke.Common;
-using Nuke.Common.Tools.DotNet;
-using static Nuke.Common.Tools.DotNet.DotNetTasks;
+using Fallout.Common;
+using Fallout.Common.Tools.DotNet;
+using static Fallout.Common.Tools.DotNet.DotNetTasks;
public partial class Build
{
diff --git a/build-support/nuke-build/Build.cs b/build-support/build/Build.cs
similarity index 88%
rename from build-support/nuke-build/Build.cs
rename to build-support/build/Build.cs
index b07d3cf9d..621926b3e 100644
--- a/build-support/nuke-build/Build.cs
+++ b/build-support/build/Build.cs
@@ -3,30 +3,25 @@
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
-using Nuke.Common;
-using Nuke.Common.CI;
-using Nuke.Common.CI.AppVeyor;
-using Nuke.Common.CI.GitHubActions;
-using Nuke.Common.Git;
-using Nuke.Common.IO;
-using Nuke.Common.ProjectModel;
-using Nuke.Common.Tools.DotNet;
-using Nuke.Common.Tools.MSBuild;
-using Nuke.Common.Utilities.Collections;
+using Fallout.Common;
+using Fallout.Common.CI;
+using Fallout.Common.CI.AppVeyor;
+using Fallout.Common.CI.GitHubActions;
+using Fallout.Common.Git;
+using Fallout.Common.IO;
+using Fallout.Common.Tools.DotNet;
+using Fallout.Common.Tools.MSBuild;
+using Fallout.Common.Utilities.Collections;
+using Fallout.Solutions;
using Serilog;
-using static Nuke.Common.Tooling.ProcessTasks;
-using static Nuke.Common.Tools.DotNet.DotNetTasks;
-using static Nuke.Common.Tools.MSBuild.MSBuildTasks;
+using static Fallout.Common.Tooling.ProcessTasks;
+using static Fallout.Common.Tools.DotNet.DotNetTasks;
+using static Fallout.Common.Tools.MSBuild.MSBuildTasks;
[ShutdownDotNetAfterServerBuild]
-partial class Build : NukeBuild
+partial class Build : FalloutBuild
{
- /// Support plugins are available for:
- /// - JetBrains ReSharper https://nuke.build/resharper
- /// - JetBrains Rider https://nuke.build/rider
- /// - Microsoft VisualStudio https://nuke.build/visualstudio
- /// - Microsoft VSCode https://nuke.build/vscode
public static int Main() => Execute(x => x.Compile);
[Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")] readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release;
@@ -47,7 +42,7 @@ partial class Build : NukeBuild
AbsolutePath ExamplesDirectory => RootDirectory / "examples";
AbsolutePath ArtifactsDirectory => RootDirectory / "artifacts";
- string TagVersion => GitRepository.Tags.SingleOrDefault(x => x.StartsWith("v"))?[1..];
+ string TagVersion => GitRepository?.Tags.SingleOrDefault(x => x.StartsWith("v"))?[1..];
bool IsTaggedBuild => !string.IsNullOrWhiteSpace(TagVersion);
diff --git a/build-support/nuke-build/Configuration.cs b/build-support/build/Configuration.cs
similarity index 93%
rename from build-support/nuke-build/Configuration.cs
rename to build-support/build/Configuration.cs
index 9b22a3bd9..2e1260566 100644
--- a/build-support/nuke-build/Configuration.cs
+++ b/build-support/build/Configuration.cs
@@ -1,5 +1,5 @@
using System.ComponentModel;
-using Nuke.Common.Tooling;
+using Fallout.Common.Tooling;
[TypeConverter(typeof(TypeConverter))]
public class Configuration : Enumeration
diff --git a/build-support/nuke-build/Directory.Build.props b/build-support/build/Directory.Build.props
similarity index 100%
rename from build-support/nuke-build/Directory.Build.props
rename to build-support/build/Directory.Build.props
diff --git a/build-support/nuke-build/Directory.Build.targets b/build-support/build/Directory.Build.targets
similarity index 100%
rename from build-support/nuke-build/Directory.Build.targets
rename to build-support/build/Directory.Build.targets
diff --git a/build-support/build/_build.csproj b/build-support/build/_build.csproj
new file mode 100644
index 000000000..5ce96c526
--- /dev/null
+++ b/build-support/build/_build.csproj
@@ -0,0 +1,16 @@
+
+
+
+ Exe
+ net10.0
+
+ CS0649;CS0169
+ ..\..
+ ..\..
+
+
+
+
+
+
+
diff --git a/build-support/nuke-build/_build.csproj.DotSettings b/build-support/build/_build.csproj.DotSettings
similarity index 100%
rename from build-support/nuke-build/_build.csproj.DotSettings
rename to build-support/build/_build.csproj.DotSettings
diff --git a/build-support/nuke-build/_build.csproj b/build-support/nuke-build/_build.csproj
deleted file mode 100644
index 91bddd5f1..000000000
--- a/build-support/nuke-build/_build.csproj
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
- Exe
- net10.0
-
- CS0649;CS0169
- ..\..
- ..\..
- 1
- true
-
-
-
-
-
-
-
diff --git a/build.ps1 b/build.ps1
index 44475eee2..3ea0b34c1 100644
--- a/build.ps1
+++ b/build.ps1
@@ -13,15 +13,15 @@ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
# CONFIGURATION
###########################################################################
-$BuildProjectFile = "$PSScriptRoot\build-support\nuke-build\_build.csproj"
-$TempDirectory = "$PSScriptRoot\\.nuke\temp"
+$TempDirectory = Join-Path $PSScriptRoot '.fallout/temp'
-$DotNetGlobalFile = "$PSScriptRoot\\global.json"
+$DotNetGlobalFile = Join-Path $PSScriptRoot 'global.json'
$DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1"
$DotNetChannel = "STS"
$env:DOTNET_CLI_TELEMETRY_OPTOUT = 1
$env:DOTNET_NOLOGO = 1
+$env:DOTNET_ROLL_FORWARD = "Major"
###########################################################################
# EXECUTION
@@ -32,19 +32,17 @@ function ExecSafe([scriptblock] $cmd) {
if ($LASTEXITCODE) { exit $LASTEXITCODE }
}
-# If dotnet CLI is installed globally and it matches requested version, use for execution
+# If dotnet CLI is installed globally, use it; otherwise provision a local copy under .fallout\temp.
if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and `
- $(dotnet --version) -and $LASTEXITCODE -eq 0) {
+ $(dotnet --version) -and $LASTEXITCODE -eq 0) {
$env:DOTNET_EXE = (Get-Command "dotnet").Path
}
else {
- # Download install script
- $DotNetInstallFile = "$TempDirectory\dotnet-install.ps1"
+ $DotNetInstallFile = Join-Path $TempDirectory 'dotnet-install.ps1'
New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
(New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile)
- # If global.json exists, load expected version
if (Test-Path $DotNetGlobalFile) {
$DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json)
if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) {
@@ -52,23 +50,17 @@ else {
}
}
- # Install by channel or version
- $DotNetDirectory = "$TempDirectory\dotnet-win"
+ $DotNetDirectory = Join-Path $TempDirectory 'dotnet-win'
if (!(Test-Path variable:DotNetVersion)) {
ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }
} else {
ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }
}
- $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
+ $env:DOTNET_EXE = Join-Path $DotNetDirectory 'dotnet.exe'
$env:PATH = "$DotNetDirectory;$env:PATH"
}
Write-Output "Microsoft (R) .NET SDK version $(& $env:DOTNET_EXE --version)"
-if (Test-Path env:NUKE_ENTERPRISE_TOKEN) {
- & $env:DOTNET_EXE nuget remove source "nuke-enterprise" > $null
- & $env:DOTNET_EXE nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password $env:NUKE_ENTERPRISE_TOKEN > $null
-}
-
-ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet }
-ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments }
+ExecSafe { & $env:DOTNET_EXE tool restore }
+ExecSafe { & $env:DOTNET_EXE fallout $BuildArguments }
diff --git a/build.sh b/build.sh
index 7df2c5967..bd0eb8400 100755
--- a/build.sh
+++ b/build.sh
@@ -9,15 +9,15 @@ SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
# CONFIGURATION
###########################################################################
-BUILD_PROJECT_FILE="$SCRIPT_DIR/build-support/nuke-build/_build.csproj"
-TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp"
+TEMP_DIRECTORY="$SCRIPT_DIR/.fallout/temp"
-DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json"
+DOTNET_GLOBAL_FILE="$SCRIPT_DIR/global.json"
DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh"
DOTNET_CHANNEL="STS"
export DOTNET_CLI_TELEMETRY_OPTOUT=1
export DOTNET_NOLOGO=1
+export DOTNET_ROLL_FORWARD="Major"
###########################################################################
# EXECUTION
@@ -27,17 +27,15 @@ function FirstJsonValue {
perl -nle 'print $1 if m{"'"$1"'": "([^"]+)",?}' <<< "${@:2}"
}
-# If dotnet CLI is installed globally and it matches requested version, use for execution
+# If dotnet CLI is installed globally, use it; otherwise provision a local copy under .fallout/temp.
if [ -x "$(command -v dotnet)" ] && dotnet --version &>/dev/null; then
export DOTNET_EXE="$(command -v dotnet)"
else
- # Download install script
DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh"
mkdir -p "$TEMP_DIRECTORY"
curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL"
chmod +x "$DOTNET_INSTALL_FILE"
- # If global.json exists, load expected version
if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then
DOTNET_VERSION=$(FirstJsonValue "version" "$(cat "$DOTNET_GLOBAL_FILE")")
if [[ "$DOTNET_VERSION" == "" ]]; then
@@ -45,7 +43,6 @@ else
fi
fi
- # Install by channel or version
DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix"
if [[ -z ${DOTNET_VERSION+x} ]]; then
"$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path
@@ -58,10 +55,5 @@ fi
echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)"
-if [[ ! -z ${NUKE_ENTERPRISE_TOKEN+x} && "$NUKE_ENTERPRISE_TOKEN" != "" ]]; then
- "$DOTNET_EXE" nuget remove source "nuke-enterprise" &>/dev/null || true
- "$DOTNET_EXE" nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password "$NUKE_ENTERPRISE_TOKEN" --store-password-in-clear-text &>/dev/null || true
-fi
-
-"$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet
-"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@"
+"$DOTNET_EXE" tool restore
+exec "$DOTNET_EXE" fallout "$@"