-
Notifications
You must be signed in to change notification settings - Fork 474
Choose unique default names for func new #4929
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -270,9 +270,12 @@ public override async Task RunAsync() | |
| ConfigureAuthorizationLevel(template); | ||
| } | ||
|
|
||
| ColoredConsole.Write($"Function name: [{template.Metadata.DefaultFunctionName}] "); | ||
| var defaultFunctionName = GetUniqueDefaultFunctionName( | ||
| template.Metadata.DefaultFunctionName, | ||
| functionName => FunctionArtifactExists(functionName, FileName, template)); | ||
|
Comment on lines
+273
to
+275
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When FileName is set, FunctionArtifactExists ignores the candidate name and only checks the fixed file path. If that file already exists, every candidate returns true and GetUniqueDefaultFunctionName loops forever, hanging func new before it ever prompts. Easiest fix is to skip the uniqueness loop when FileName != null (renaming the function can't avoid a fixed-file collision anyway). Cleanest fix: var defaultFunctionName = FileName != null
? template.Metadata.DefaultFunctionName
: GetUniqueDefaultFunctionName(
template.Metadata.DefaultFunctionName,
functionName => FunctionArtifactExists(functionName, FileName, template)); |
||
| ColoredConsole.Write($"Function name: [{defaultFunctionName}] "); | ||
| FunctionName = FunctionName ?? Console.ReadLine(); | ||
| FunctionName = string.IsNullOrEmpty(FunctionName) ? template.Metadata.DefaultFunctionName : FunctionName; | ||
| FunctionName = string.IsNullOrEmpty(FunctionName) ? defaultFunctionName : FunctionName; | ||
| await _templatesManager.Deploy(FunctionName, FileName, template); | ||
| PerformPostDeployTasks(FunctionName, Language); | ||
| } | ||
|
|
@@ -470,6 +473,45 @@ private void ConfigureAuthorizationLevel(Template template) | |
| } | ||
| } | ||
|
|
||
| internal static string GetUniqueDefaultFunctionName(string defaultFunctionName, Func<string, bool> functionExists) | ||
| { | ||
| if (!functionExists(defaultFunctionName)) | ||
| { | ||
| return defaultFunctionName; | ||
| } | ||
|
|
||
| var index = 1; | ||
| string candidate; | ||
| do | ||
| { | ||
| candidate = $"{defaultFunctionName}{index}"; | ||
| index++; | ||
| } | ||
| while (functionExists(candidate)); | ||
|
|
||
| return candidate; | ||
| } | ||
|
|
||
| private static bool FunctionArtifactExists(string functionName, string fileName, Template template) | ||
| { | ||
| if (IsNodeV4Template(template)) | ||
| { | ||
| return template.Files | ||
| .Where(file => !file.Key.EndsWith(".dat")) | ||
| .Select(file => fileName ?? file.Key.Replace("%functionName%", functionName)) | ||
| .Any(name => FileSystemHelpers.FileExists( | ||
| Path.Combine(Environment.CurrentDirectory, "src", "functions", name))); | ||
| } | ||
|
|
||
| return FileSystemHelpers.DirectoryExists(Path.Combine(Environment.CurrentDirectory, functionName)); | ||
| } | ||
|
|
||
| private static bool IsNodeV4Template(Template template) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This exact code/check already exists inlined in TemplatesManager.cs:145 - you should extract this a shared helper instead of duplicating |
||
| { | ||
| return template.Id.EndsWith("JavaScript-4.x", StringComparison.OrdinalIgnoreCase) || | ||
| template.Id.EndsWith("TypeScript-4.x", StringComparison.OrdinalIgnoreCase); | ||
| } | ||
|
|
||
| private bool InferAndUpdateLanguage(WorkerRuntime workerRuntime) | ||
| { | ||
| switch (workerRuntime) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| // Copyright (c) .NET Foundation. All rights reserved. | ||
| // Licensed under the MIT License. See LICENSE in the project root for license information. | ||
|
|
||
| using System; | ||
| using System.Collections.Generic; | ||
| using Azure.Functions.Cli.Actions.LocalActions; | ||
| using Xunit; | ||
|
|
||
| namespace Azure.Functions.Cli.UnitTests.ActionsTests | ||
| { | ||
| public class CreateFunctionActionTests | ||
| { | ||
| [Fact] | ||
| public void GetUniqueDefaultFunctionName_ReturnsDefault_WhenAvailable() | ||
| { | ||
| var result = CreateFunctionAction.GetUniqueDefaultFunctionName("HttpTrigger", _ => false); | ||
|
|
||
| Assert.Equal("HttpTrigger", result); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void GetUniqueDefaultFunctionName_IncrementsUntilNameIsAvailable() | ||
| { | ||
| var existingNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase) | ||
| { | ||
| "HttpTrigger", | ||
| "HttpTrigger1", | ||
| "HttpTrigger2" | ||
| }; | ||
|
|
||
| var result = CreateFunctionAction.GetUniqueDefaultFunctionName("HttpTrigger", existingNames.Contains); | ||
|
|
||
| Assert.Equal("HttpTrigger3", result); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now this PR only covers the traditional/Node v4 path, .NET (in-proc and isolated) and the Python v2 programming model take their own branches earlier in RunAsync and still silently prompt with a colliding default. Please extend the uniqueness behavior to those two paths as well.
.NET (in-proc & isolated) branch: lines 144–162 (if (WorkerRuntimeLanguageHelper.IsDotnet(_workerRuntime) && !Csx)), default name is set at line 158 (FunctionName = string.IsNullOrEmpty(FunctionName) ? TemplateName : FunctionName;).
Python v2 (new programming model) branch: lines 165–234 (else if (IsNewPythonProgrammingModel())), default name is resolved at lines 227–230 (if (string.IsNullOrEmpty(FunctionName)) FunctionName = providedInputs[GetFunctionNameParamId];).
Both bypass the new GetUniqueDefaultFunctionName call