diff --git a/src/Azure.Functions.Cli/Azure.Functions.Cli.csproj b/src/Azure.Functions.Cli/Azure.Functions.Cli.csproj index ac9997361..fa9c0554d 100644 --- a/src/Azure.Functions.Cli/Azure.Functions.Cli.csproj +++ b/src/Azure.Functions.Cli/Azure.Functions.Cli.csproj @@ -114,6 +114,9 @@ $(AssemblyName).Dockerfile.python3.11 + + $(AssemblyName).Dockerfile.python3.12 + $(AssemblyName).Dockerfile.javascript diff --git a/src/Azure.Functions.Cli/Common/Constants.cs b/src/Azure.Functions.Cli/Common/Constants.cs index 47b7be41c..52eb0b096 100644 --- a/src/Azure.Functions.Cli/Common/Constants.cs +++ b/src/Azure.Functions.Cli/Common/Constants.cs @@ -180,6 +180,8 @@ public static class DockerImages public const string LinuxPython39ImageAmd64 = "mcr.microsoft.com/azure-functions/python:3.0.15066-python3.9-buildenv"; public const string LinuxPython310ImageAmd64 = "mcr.microsoft.com/azure-functions/python:4-python3.10-buildenv"; public const string LinuxPython311ImageAmd64 = "mcr.microsoft.com/azure-functions/python:4-python3.11-buildenv"; + public const string LinuxPython312ImageAmd64 = "mcr.microsoft.com/azure-functions/python:4-python3.12-buildenv"; + } public static class StaticResourcesNames diff --git a/src/Azure.Functions.Cli/Helpers/PythonHelpers.cs b/src/Azure.Functions.Cli/Helpers/PythonHelpers.cs index c6ff82076..65595232e 100644 --- a/src/Azure.Functions.Cli/Helpers/PythonHelpers.cs +++ b/src/Azure.Functions.Cli/Helpers/PythonHelpers.cs @@ -167,7 +167,7 @@ public static void AssertPythonVersion(WorkerLanguageVersionInfo pythonVersion, { if (pythonVersion?.Version == null) { - var message = "Could not find a Python version. Python 3.6.x, 3.7.x, 3.8.x, 3.9.x, 3.10.x or 3.11.x is recommended, and used in Azure Functions."; + var message = "Could not find a Python version. 3.7.x, 3.8.x, 3.9.x, 3.10.x, 3.11.x or 3.12.x is recommended, and used in Azure Functions."; if (errorIfNoVersion) throw new CliException(message); ColoredConsole.WriteLine(WarningColor(message)); return; @@ -175,23 +175,23 @@ public static void AssertPythonVersion(WorkerLanguageVersionInfo pythonVersion, ColoredConsole.WriteLine(AdditionalInfoColor($"Found Python version {pythonVersion.Version} ({pythonVersion.ExecutablePath}).")); - // Python 3.[6|7|8|9|10|11] (supported) + // Python 3.[7|8|9|10|11|12] (supported) if (IsVersionSupported(pythonVersion)) { return; } - // Python 3.x (but not 3.[6|7|8|9|10|11]), not recommended, may fail. E.g.: 3.4, 3.5. + // Python 3.x (but not 3.[7|8|9|10|11|12]), not recommended, may fail. E.g.: 3.4, 3.5. if (pythonVersion.Major == 3) { if (errorIfNotSupported) - throw new CliException($"Python 3.6.x to 3.11.x is required for this operation. " + - $"Please install Python 3.6, 3.7, 3.8, 3.9, 3.10 or 3.11 and use a virtual environment to switch to Python 3.6, 3.7, 3.8, 3.9, 3.10 or 3.11."); - ColoredConsole.WriteLine(WarningColor("Python 3.6.x, 3.7.x, 3.8.x, 3.9.x, 3.10.x or 3.11.x is recommended, and used in Azure Functions.")); + throw new CliException($"Python 3.7.x to 3.12.x is required for this operation. " + + $"Please install Python 3.7, 3.8, 3.9, 3.10, 3.11 or 3.12 and use a virtual environment to switch to Python 3.7, 3.8, 3.9, 3.10, 3.11 or 3.12."); + ColoredConsole.WriteLine(WarningColor("Python 3.7.x, 3.8.x, 3.9.x, 3.10.x, 3.11.x or 3.12.x is recommended, and used in Azure Functions.")); } // No Python 3 - var error = "Python 3.x (recommended version 3.[6|7|8|9|10|11]) is required."; + var error = "Python 3.x (recommended version 3.[7|8|9|10|11|12]) is required."; if (errorIfNoVersion) throw new CliException(error); ColoredConsole.WriteLine(WarningColor(error)); } @@ -225,6 +225,7 @@ public static async Task GetEnvironmentPythonVersion( var python39GetVersionTask = GetVersion("python3.9"); var python310GetVersionTask = GetVersion("python3.10"); var python311GetVersionTask = GetVersion("python3.11"); + var python312GetVersionTask = GetVersion("python3.12"); var versions = new List { @@ -237,6 +238,7 @@ public static async Task GetEnvironmentPythonVersion( await python39GetVersionTask, await python310GetVersionTask, await python311GetVersionTask, + await python312GetVersionTask }; // Highest preference -- Go through the list, if we find the first python 3.6 or python 3.7 worker, we prioritize that. @@ -559,6 +561,8 @@ public static Task GetDockerInitFileContent(WorkerLanguageVersionInfo in return StaticResources.DockerfilePython310; case 11: return StaticResources.DockerfilePython311; + case 12: + return StaticResources.DockerfilePython312; } } return StaticResources.DockerfilePython37; @@ -582,6 +586,8 @@ private static string GetBuildNativeDepsEnvironmentImage(WorkerLanguageVersionIn return Constants.DockerImages.LinuxPython310ImageAmd64; case 11: return Constants.DockerImages.LinuxPython311ImageAmd64; + case 12: + return Constants.DockerImages.LinuxPython312ImageAmd64; } } return Constants.DockerImages.LinuxPython36ImageAmd64; @@ -593,12 +599,12 @@ private static bool IsVersionSupported(WorkerLanguageVersionInfo info) { switch (info?.Minor) { + case 12: case 11: case 10: case 9: case 8: - case 7: - case 6: return true; + case 7: return true; default: return false; } } else return false; @@ -606,11 +612,11 @@ private static bool IsVersionSupported(WorkerLanguageVersionInfo info) public static bool IsLinuxFxVersionRuntimeVersionMatched(string linuxFxVersion, int? major, int? minor) { - // No linux fx version will default to python 3.6 + // No linux fx version will default to python 3.11 if (string.IsNullOrEmpty(linuxFxVersion)) { - // Match if version is 3.6 - return major == 3 && minor == 6; + // Match if version is 3.11 + return major == 3 && minor == 11; } // Only validate on LinuxFxVersion that follows the pattern PYTHON| else if (!linuxFxVersion.StartsWith("PYTHON|", StringComparison.OrdinalIgnoreCase)) diff --git a/src/Azure.Functions.Cli/StaticResources/Dockerfile.python3.12 b/src/Azure.Functions.Cli/StaticResources/Dockerfile.python3.12 new file mode 100644 index 000000000..ae1f86f01 --- /dev/null +++ b/src/Azure.Functions.Cli/StaticResources/Dockerfile.python3.12 @@ -0,0 +1,11 @@ +# To enable ssh & remote debugging on app service change the base image to the one below +# FROM mcr.microsoft.com/azure-functions/python:4-python3.12-appservice +FROM mcr.microsoft.com/azure-functions/python:4-python3.12 + +ENV AzureWebJobsScriptRoot=/home/site/wwwroot \ + AzureFunctionsJobHost__Logging__Console__IsEnabled=true + +COPY requirements.txt / +RUN pip install -r /requirements.txt + +COPY . /home/site/wwwroot diff --git a/src/Azure.Functions.Cli/StaticResources/StaticResources.cs b/src/Azure.Functions.Cli/StaticResources/StaticResources.cs index 70a07c1a9..3f5ae6e83 100644 --- a/src/Azure.Functions.Cli/StaticResources/StaticResources.cs +++ b/src/Azure.Functions.Cli/StaticResources/StaticResources.cs @@ -56,6 +56,8 @@ public static async Task GetValue(string name) public static Task DockerfilePython311 => GetValue("Dockerfile.python3.11"); + public static Task DockerfilePython312 => GetValue("Dockerfile.python3.12"); + public static Task DockerfilePowershell7 => GetValue("Dockerfile.powershell7"); public static Task DockerfilePowershell72 => GetValue("Dockerfile.powershell7.2"); diff --git a/test/Azure.Functions.Cli.Tests/PythonHelperTests.cs b/test/Azure.Functions.Cli.Tests/PythonHelperTests.cs index 28936f255..9c19b667f 100644 --- a/test/Azure.Functions.Cli.Tests/PythonHelperTests.cs +++ b/test/Azure.Functions.Cli.Tests/PythonHelperTests.cs @@ -44,7 +44,6 @@ public async void WorkerInfoRuntimeShouldBePython() [Theory] [InlineData("DOCKER|mcr.microsoft.com/azure-functions/python", 3, 9, true)] [InlineData("", 3, 7, false)] - [InlineData("", 3, 6, true)] [InlineData("PYTHON|3.6", 3, 6, true)] [InlineData("PYTHON|3.6", 3, 7, false)] [InlineData("PYTHON|3.7", 3, 6, false)] @@ -54,6 +53,9 @@ public async void WorkerInfoRuntimeShouldBePython() [InlineData("PYTHON|3.9", null, 9, false)] [InlineData("PYTHON|3.9", 3, null, false)] [InlineData("PYTHON|3.9", null, null, false)] + [InlineData("Python|3.10", 3, 10, true)] + [InlineData("Python|3.11", 3, 11, true)] + [InlineData("Python|3.12", 3, 12, true)] public void ShouldHaveMatchingLinuxFxVersion(string linuxFxVersion, int major, int minor, bool expectedResult) { bool result = PythonHelpers.IsLinuxFxVersionRuntimeVersionMatched(linuxFxVersion, major, minor); @@ -66,12 +68,13 @@ public void ShouldHaveMatchingLinuxFxVersion(string linuxFxVersion, int major, i [Theory] [InlineData("2.7.10", true)] [InlineData("3.5.5", true)] - [InlineData("3.6.8b", false)] + [InlineData("3.6.8b", true)] [InlineData("3.7.2", false)] [InlineData("3.8.0", false)] [InlineData("3.9.0", false)] [InlineData("3.10.0", false)] [InlineData("3.11.0", false)] + [InlineData("3.12.0", false)] public void AssertPythonVersion(string pythonVersion, bool expectException) { WorkerLanguageVersionInfo worker = new WorkerLanguageVersionInfo(WorkerRuntime.python, pythonVersion, "python"); @@ -93,11 +96,11 @@ public SkipIfPythonNonExistFact() string[] pythons; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - pythons = new string[] { "python.exe", "python3.exe", "python36.exe", "python37.exe", "python38.exe", "python39.exe", "python310.exe", "python311.exe", "py.exe" }; + pythons = new string[] { "python.exe", "python3.exe", "python37.exe", "python38.exe", "python39.exe", "python310.exe", "python311.exe", "python312.exe", "py.exe" }; } else { - pythons = new string[] { "python", "python3", "python36", "python37", "python38", "python39", "python310", "python311" }; + pythons = new string[] { "python", "python3", "python37", "python38", "python39", "python310", "python311", "python312" }; } string pythonExe = pythons.FirstOrDefault(p => CheckIfPythonExist(p));