Skip to content
Merged
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: 4 additions & 0 deletions docs/debug-with-host.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ export FUNC_CLI=<path-to-published-cli>

# Start the host inside the test app directory
$FUNC_CLI start

# Or, you can use an alias instead
alias testfunc="<path-to-published-cli>"
testfunc start
```

Windows:
Expand Down
18 changes: 2 additions & 16 deletions release_notes.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Azure Functions CLI 4.6.0
# Azure Functions CLI 4.7.0

#### Host Version

Expand All @@ -9,18 +9,4 @@

#### Changes

- Fix .gitignore to allow PowerShell module bin folders (#4574)
- Refactor to use msbuild for determining .NET target framework & add support multiple TFMs (#4715)
- When using `func init --docker-only` on a .NET project with multiple target frameworks, the CLI will now
prompt the user to select which target framework to use for the Dockerfile.
- Enhanced dotnet installation discovery by adopting the same `Muxer` logic used by the .NET SDK itself (#4732)
- Update .NET templates package version to 4.0.5337 (#4728)
- Fix `func pack --build-native-deps` failure on Windows for Python 3.13+ (#4742)
- Add deprecation warning for extension bundles during function app publish (#4700)
- Update the TypeScript project template to improve interoperability (#4739)
- Upgrade `typescript` from `^4.0.0` to `^5.0.0`
- Add `"esModuleInterop": true` option to `tsconfig.json`
- Cleaned up `func --help` output and fixed validation errors when using the `--help` flag for specific commands (#4748)
- Improved `func init --help` output to better display options for each worker runtime (#4748)
- Fix F# project & template initialization via `func init | new` (#4749)
- Log a warning if remote build is used for Python 3.14 flex app (#4755)
- Added end-of-life warnings for all runtime versions during `func azure functionapp publish`. (#4760)
45 changes: 7 additions & 38 deletions src/Cli/func/Actions/AzureActions/PublishFunctionAppAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@ public override async Task RunAsync()
// Get the WorkerRuntime
var workerRuntime = GlobalCoreToolsSettings.CurrentWorkerRuntime;

// Get Stacks once for both .NET version determination and EOL checking
var stacks = await AzureHelper.GetFunctionsStacks(AccessToken, ManagementURL);

// Determine the appropriate default targetFramework
// TODO: Include proper steps for publishing a .NET Framework 4.8 application
if (workerRuntime == WorkerRuntime.DotnetIsolated)
Expand All @@ -182,16 +185,8 @@ public override async Task RunAsync()

if (majorDotnetVersion != null)
{
// Get Stacks
var stacks = await AzureHelper.GetFunctionsStacks(AccessToken, ManagementURL);
var runtimeSettings = stacks.GetRuntimeSettings(majorDotnetVersion.Value, out bool isLTS);

ShowEolMessage(stacks, runtimeSettings, majorDotnetVersion.Value);

// This is for future proofing with stacks API for future dotnet versions.
if (runtimeSettings != null &&
(runtimeSettings.IsDeprecated == null || runtimeSettings.IsDeprecated == false) &&
(runtimeSettings.IsDeprecatedForRuntime == null || runtimeSettings.IsDeprecatedForRuntime == false))
if (!Services.RuntimeEolChecker.IsDotnetVersionDeprecated(stacks, majorDotnetVersion.Value))
{
_requiredNetFrameworkVersion = $"{majorDotnetVersion}.0";
}
Expand All @@ -210,6 +205,9 @@ public override async Task RunAsync()
// We do not change the default targetFramework if no .csproj file is found
}

// Check for EOL warnings for all runtimes
Services.RuntimeEolChecker.CheckAndWarnIfApproachingEol(stacks, workerRuntime, functionApp);

// Check for any additional conditions or app settings that need to change
// before starting any of the publish activity.
var additionalAppSettings = await ValidateFunctionAppPublish(functionApp, workerRuntime, functionAppRoot);
Expand Down Expand Up @@ -1466,35 +1464,6 @@ private string GetLogPrefix()
return $"[{DateTime.UtcNow.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffZ", CultureInfo.InvariantCulture)}] ".ToString();
}

private void ShowEolMessage(FunctionsStacks stacks, WindowsRuntimeSettings currentRuntimeSettings, int? majorDotnetVersion)
{
try
{
if (currentRuntimeSettings.IsDeprecated == true || currentRuntimeSettings.IsDeprecatedForRuntime == true)
{
var nextDotnetVersion = stacks.GetNextDotnetVersion(majorDotnetVersion.Value);
if (nextDotnetVersion != null)
{
var warningMessage = EolMessages.GetAfterEolUpdateMessageDotNet(majorDotnetVersion.ToString(), nextDotnetVersion.ToString(), currentRuntimeSettings.EndOfLifeDate.Value);
ColoredConsole.WriteLine(WarningColor(warningMessage));
}
}
else if (StacksApiHelper.IsInNextSixMonths(currentRuntimeSettings.EndOfLifeDate))
{
var nextDotnetVersion = stacks.GetNextDotnetVersion(majorDotnetVersion.Value);
if (nextDotnetVersion != null)
{
var warningMessage = EolMessages.GetEarlyEolUpdateMessageDotNet(majorDotnetVersion.ToString(), nextDotnetVersion.ToString(), currentRuntimeSettings.EndOfLifeDate.Value);
ColoredConsole.WriteLine(WarningColor(warningMessage));
}
}
}
catch (Exception)
{
// ignore. Failure to show the EOL message should not fail the deployment.
}
}

// For testing
internal class AzureHelperService
{
Expand Down
10 changes: 7 additions & 3 deletions src/Cli/func/Actions/LocalActions/InitAction/InitAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -643,14 +643,18 @@ private async Task ShowEolMessage()
return;
}

if (currentRuntimeSettings.IsDeprecated == true || currentRuntimeSettings.IsDeprecatedForRuntime == true)
// Check if EOL date has already passed
var isAlreadyEol = currentRuntimeSettings.EndOfLifeDate.HasValue &&
currentRuntimeSettings.EndOfLifeDate.Value < DateTime.UtcNow;

if (isAlreadyEol || currentRuntimeSettings.IsDeprecated == true || currentRuntimeSettings.IsDeprecatedForRuntime == true)
{
var warningMessage = EolMessages.GetAfterEolCreateMessageDotNet(majorDotnetVersion.ToString(), currentRuntimeSettings.EndOfLifeDate.Value);
var warningMessage = EolMessages.GetAfterEolCreateMessage(".NET", majorDotnetVersion.ToString(), currentRuntimeSettings.EndOfLifeDate.Value);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: ".NET" can be a const

ColoredConsole.WriteLine(WarningColor(warningMessage));
}
else if (StacksApiHelper.IsInNextSixMonths(currentRuntimeSettings.EndOfLifeDate))
{
var warningMessage = EolMessages.GetEarlyEolCreateMessageForDotNet(majorDotnetVersion.ToString(), currentRuntimeSettings.EndOfLifeDate.Value);
var warningMessage = EolMessages.GetEarlyEolCreateMessage(".NET", majorDotnetVersion.ToString(), currentRuntimeSettings.EndOfLifeDate.Value);
ColoredConsole.WriteLine(WarningColor(warningMessage));
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Cli/func/Directory.Version.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>

<PropertyGroup>
<VersionPrefix>4.6.0</VersionPrefix>
<VersionPrefix>4.7.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
<UpdateBuildNumber>true</UpdateBuildNumber>
</PropertyGroup>
Expand Down
46 changes: 37 additions & 9 deletions src/Cli/func/Helpers/EolMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,57 @@ namespace Azure.Functions.Cli.Helpers
{
internal class EolMessages
{
public static string GetEarlyEolCreateMessageForDotNet(string stackVersion, DateTime eol, string link = "")
/// <summary>
/// Gets a message for when a runtime version will reach EOL in the future (create/init scenario).
/// </summary>
public static string GetEarlyEolCreateMessage(string runtimeName, string version, DateTime eol, string link = "")
{
return $".NET {stackVersion} will reach EOL on {FormatDate(eol)} and will no longer be supported. {link}";
return $"{runtimeName} {version} will reach end-of-life on {FormatDate(eol)} and will no longer be supported. {link}".Trim();
}

public static string GetAfterEolCreateMessageDotNet(string stackVersion, DateTime eol, string link = "")
/// <summary>
/// Gets a message for when a runtime version has already reached EOL (create/init scenario).
/// </summary>
public static string GetAfterEolCreateMessage(string runtimeName, string version, DateTime eol, string link = "")
{
return $".NET {stackVersion} has reached EOL on {FormatDate(eol)} and is no longer supported. {link}";
return $"{runtimeName} {version} has reached end-of-life on {FormatDate(eol)} and is no longer supported. {link}".Trim();
}

public static string GetEarlyEolUpdateMessageDotNet(string currentStackVersion, string nextStackVersion, DateTime eol, string link = "")
/// <summary>
/// Gets an upgrade message for when a runtime version will reach EOL in the future (publish/update scenario).
/// </summary>
public static string GetEarlyEolUpgradeMessage(string runtimeName, string currentVersion, string nextVersion, DateTime eol, string link = "")
{
return $"Upgrade your app to .NET {nextStackVersion} as .NET {currentStackVersion} will reach EOL on {FormatDate(eol)} and will no longer be supported. {link}";
return $"Upgrade to {runtimeName} {nextVersion} as {runtimeName} {currentVersion} will reach end-of-life on {FormatDate(eol)} and will no longer be supported. Learn more: {link}".Trim();
}

public static string GetAfterEolUpdateMessageDotNet(string currentStackVersion, string nextStackVersion, DateTime eol, string link = "")
/// <summary>
/// Gets an upgrade message for when a runtime version has already reached EOL (publish/update scenario).
/// </summary>
public static string GetAfterEolUpgradeMessage(string runtimeName, string currentVersion, string nextVersion, DateTime eol, string link = "")
{
return $"Upgrade your app to .NET {nextStackVersion} as .NET {currentStackVersion} has reached EOL on {FormatDate(eol)} and is no longer supported. {link}";
return $"Upgrade to {runtimeName} {nextVersion} as {runtimeName} {currentVersion} has reached end-of-life on {FormatDate(eol)} and is no longer be supported. Learn more: {link}".Trim();
}

/// <summary>
/// Gets a generic message without upgrade recommendation for when a runtime version will reach EOL.
/// </summary>
public static string GetEarlyEolMessage(string runtimeName, string version, DateTime eol, string link = "")
{
return $"{runtimeName} {version} will reach end-of-life on {FormatDate(eol)} and will no longer be supported. Learn more: {link}".Trim();
}

/// <summary>
/// Gets a generic message without upgrade recommendation for when a runtime version has reached EOL.
/// </summary>
public static string GetAfterEolMessage(string runtimeName, string version, DateTime eol, string link = "")
{
return $"{runtimeName} {version} has reached end-of-life on {FormatDate(eol)} and is no longer supported. Learn more: {link}".Trim();
}

private static string FormatDate(DateTime dateTime)
{
return dateTime.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
return dateTime.ToString("MMMM dd yyyy", CultureInfo.CurrentCulture);
}
}
}
Loading
Loading