diff --git a/source/Calamari.Common/Features/Scripting/DotnetScript/DotnetScriptExecutor.cs b/source/Calamari.Common/Features/Scripting/DotnetScript/DotnetScriptExecutor.cs index 1df9532fc5..9e783acafd 100644 --- a/source/Calamari.Common/Features/Scripting/DotnetScript/DotnetScriptExecutor.cs +++ b/source/Calamari.Common/Features/Scripting/DotnetScript/DotnetScriptExecutor.cs @@ -11,6 +11,8 @@ namespace Calamari.Common.Features.Scripting.DotnetScript { public class DotnetScriptExecutor : ScriptExecutor { + const string DotnetRollForwardVariableName = "DOTNET_ROLL_FORWARD"; + readonly ICommandLineRunner commandLineRunner; public DotnetScriptExecutor(ICommandLineRunner commandLineRunner, ILog log): base(log) @@ -37,13 +39,37 @@ protected override IEnumerable PrepareExecution(Script script, bool.TryParse(variables.Get("Octopus.Action.Script.CSharp.BypassIsolation", "false"), out var bypassDotnetScriptIsolation); var cli = CreateCommandLineInvocation(executable, arguments, !string.IsNullOrWhiteSpace(localDotnetScriptPath)); - cli.EnvironmentVars = environmentVars; + cli.EnvironmentVars = WithDotnetRollForward(environmentVars); cli.WorkingDirectory = workingDirectory; cli.Isolate = !bypassDotnetScriptIsolation; yield return new ScriptExecution(cli, otherTemporaryFiles.Concat(new[] { bootstrapFile, configurationFile })); } + /// + /// dotnet-script is a framework-dependent application - the bundled copy targets + /// Microsoft.NETCore.App 8.0.0. By default a framework-dependent app will not roll forward + /// across a major version, so on a machine that only has a newer runtime installed it fails + /// to launch with "You must install or update .NET to run this application". + /// + /// Calamari itself is published self-contained and carries no such requirement; this affects + /// only the separate dotnet-script process. Setting DOTNET_ROLL_FORWARD=Major lets it run on + /// whatever newer runtime is present, so C# script steps don't additionally require the exact + /// runtime dotnet-script was built against. + /// + static Dictionary WithDotnetRollForward(Dictionary? environmentVars) + { + var vars = environmentVars == null + ? new Dictionary() + : new Dictionary(environmentVars); + + // Don't override an explicit value - the surrounding environment may have set one deliberately. + if (!vars.ContainsKey(DotnetRollForwardVariableName)) + vars[DotnetRollForwardVariableName] = "Major"; + + return vars; + } + private string GetExecutable(string? localDotnetScriptPath, string bundledExecutable) { return string.IsNullOrWhiteSpace(localDotnetScriptPath)