From ebd3fc95da4ba359b33d1e111087d1ed6416b381 Mon Sep 17 00:00:00 2001 From: Lukas Gasselsberger | alu-one Date: Mon, 20 Jul 2026 13:04:07 +0200 Subject: [PATCH 1/2] Add a cleanup step for bootstrapper files to remove stale `NUKE_ENTERPRISE_TOKEN` handling --- src/Fallout.Migrate/Migration.cs | 1 + .../Steps/CleanupBootstrapScriptsStep.cs | 62 +++++++++++++++ .../MigrationIntegrationSpecs.cs | 8 ++ .../ScriptRewriterSpecs.cs | 76 +++++++++++++++++++ 4 files changed, 147 insertions(+) create mode 100644 src/Fallout.Migrate/Steps/CleanupBootstrapScriptsStep.cs diff --git a/src/Fallout.Migrate/Migration.cs b/src/Fallout.Migrate/Migration.cs index aa8d6e0ed..55f2ab655 100644 --- a/src/Fallout.Migrate/Migration.cs +++ b/src/Fallout.Migrate/Migration.cs @@ -30,6 +30,7 @@ internal sealed class Migration(AbsolutePath rootDirectory, bool dryRun, TextWri new BumpDotNetVersionStep(), new RewriteCsFilesStep(), new RewriteBootstrapScriptsStep(), + new CleanupBootstrapScriptsStep(), new RenameNukeDirectoryStep() ]; diff --git a/src/Fallout.Migrate/Steps/CleanupBootstrapScriptsStep.cs b/src/Fallout.Migrate/Steps/CleanupBootstrapScriptsStep.cs new file mode 100644 index 000000000..13d438941 --- /dev/null +++ b/src/Fallout.Migrate/Steps/CleanupBootstrapScriptsStep.cs @@ -0,0 +1,62 @@ +using System; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Fallout.Common.IO; +using Fallout.Migrate.Common; + +namespace Fallout.Migrate.Steps; + +internal partial class CleanupBootstrapScriptsStep : IMigrationStep +{ + private static readonly Regex nukeEnterprisePattern = new(@"\bNUKE_ENTERPRISE_TOKEN\b", RegexOptions.Compiled); + + public Task ExecuteAsync(MigrationContext context, Summary summary) + { + foreach (var file in new[] + { + "build.sh", + "build.ps1" + }) + { + var path = context.RootDirectory / file; + if (path.FileExists()) + { + MigrationFileOperations.ApplyRewrite(context, path, Cleanup, summary); + } + } + + return Task.CompletedTask; + } + + internal static RewriteResult Cleanup(string content) + { + if (!nukeEnterprisePattern.IsMatch(content)) + { + return new(content, 0); + } + + string newline = + GetLineFeedRegex().Match(content).Value is { Length: > 0 } value + ? value + : Environment.NewLine; + + var lines = GetLineFeedRegex().Split(content).ToList(); + + var indexOfEnterpriseEnvVarCheck = lines.FindIndex(line => line.Contains("NUKE_ENTERPRISE_TOKEN")); + var endOfIfBlock = lines.FindIndex(indexOfEnterpriseEnvVarCheck, + line => line.Trim() == "}" || line.Trim() == "fi"); + + if (lines[endOfIfBlock + 1].Trim() == "") + { + endOfIfBlock++; + } + + lines.RemoveRange(indexOfEnterpriseEnvVarCheck, endOfIfBlock - indexOfEnterpriseEnvVarCheck + 1); + + return new(string.Join(newline, lines), 1); + } + + [GeneratedRegex(@"\r\n|\n|\r")] + private static partial Regex GetLineFeedRegex(); +} diff --git a/tests/Fallout.Migrate.Specs/MigrationIntegrationSpecs.cs b/tests/Fallout.Migrate.Specs/MigrationIntegrationSpecs.cs index 53a937e8e..68f24aae2 100644 --- a/tests/Fallout.Migrate.Specs/MigrationIntegrationSpecs.cs +++ b/tests/Fallout.Migrate.Specs/MigrationIntegrationSpecs.cs @@ -36,6 +36,7 @@ public async Task MigratesVanillaConsumerRepo() buildSh.Should().Contain("dotnet fallout"); buildSh.Should().Contain("FALLOUT_TELEMETRY_OPTOUT"); buildSh.Should().Contain(".fallout/temp"); + buildSh.Should().NotContain("if [[ ! -z ${NUKE_ENTERPRISE_TOKEN+x} && \"$NUKE_ENTERPRISE_TOKEN\" != \"\" ]]; then"); // .nuke/ moved to .fallout/. Directory.Exists(Path.Combine(temp, ".nuke")).Should().BeFalse(); @@ -182,6 +183,13 @@ class Build : NukeBuild #!/usr/bin/env bash export NUKE_TELEMETRY_OPTOUT=1 TEMP_DIRECTORY="$SCRIPT_DIR/.nuke/temp" + 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 nuke "$@" """, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); diff --git a/tests/Fallout.Migrate.Specs/ScriptRewriterSpecs.cs b/tests/Fallout.Migrate.Specs/ScriptRewriterSpecs.cs index f9f4956a2..5bcc36a14 100644 --- a/tests/Fallout.Migrate.Specs/ScriptRewriterSpecs.cs +++ b/tests/Fallout.Migrate.Specs/ScriptRewriterSpecs.cs @@ -45,4 +45,80 @@ public void LeavesPlainWordNukeAlone() var result = ScriptRewriter.Rewrite(input); result.EditCount.Should().Be(0); } + + [Fact] + public void Removes_Nuke_enterprise_unix_bootstrapper_leftovers() + { + const string input = + """ + 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 -- "$@" + """; + + var result = CleanupBootstrapScriptsStep.Cleanup(input); + result.EditCount.Should().Be(1); + result.Content.Should().Be( + """ + echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)" + + "$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 -- "$@" + """); + } + + [Fact] + public void Removes_Nuke_enterprise_windows_bootstrapper_leftovers() + { + const string input = + """ + 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 } + """; + + var result = CleanupBootstrapScriptsStep.Cleanup(input); + result.EditCount.Should().Be(1); + result.Content.Should().Be( + """ + Write-Output "Microsoft (R) .NET SDK version $(& $env:DOTNET_EXE --version)" + + 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 } + """); + } + + [Fact] + public void Leaves_bootstrapper_scripts_without_leftovers_alone() + { + const string input = + """ + echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)" + + "$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 -- "$@" + """; + + var result = CleanupBootstrapScriptsStep.Cleanup(input); + result.EditCount.Should().Be(0); + result.Content.Should().Be( + """ + echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)" + + "$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 -- "$@" + """); + } } From 7c062b2a871dcadbdfd3781884f4c6877b15faa3 Mon Sep 17 00:00:00 2001 From: Lukas Gasselsberger | alu-one Date: Mon, 20 Jul 2026 20:18:53 +0200 Subject: [PATCH 2/2] Add migration docs --- docs/migration/from-nuke.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/migration/from-nuke.md b/docs/migration/from-nuke.md index bca967975..4ac3757ef 100644 --- a/docs/migration/from-nuke.md +++ b/docs/migration/from-nuke.md @@ -68,6 +68,7 @@ If your build had previously worked against NUKE, it should now work against Fal | Base interface name | `: INukeBuild` | `: IFalloutBuild` | | MSBuild properties in `_build.csproj` | ``, `` | ``, `` | | Bootstrap scripts | `dotnet nuke`, `NUKE_TELEMETRY_OPTOUT`, `.nuke/temp` | `dotnet fallout`, `FALLOUT_TELEMETRY_OPTOUT`, `.fallout/temp` | +| Removes stale Nuke Enterprise NuGet source | The whole env var check for `NUKE_ENTERPRISE_TOKEN` and its handling | The bootstrapper files (`build.sh` and `build.ps1`) without these `if`'s | | Config directory | `.nuke/` | `.fallout/` (contents preserved) | The 1:1 namespace prefix swap is the only structural change. Type names (other than `NukeBuild` / `INukeBuild`) keep their identifiers — `[Parameter]`, `[Solution]`, `[GitHubActions]`, `Solution`, `GitRepository`, etc. all stay the same.