Skip to content

Commit b026a0c

Browse files
Merge branch 'v3.x' into use-next-available-port
2 parents 5532e73 + d6dfa46 commit b026a0c

17 files changed

+190
-61
lines changed

CODEOWNERS

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# =======================================================
2+
# See https://help.github.com/articles/about-codeowners/
3+
# for more info about CODEOWNERS file
4+
#
5+
# It uses the same pattern rule for gitignore file
6+
# https://git-scm.com/docs/gitignore#_pattern_format
7+
#
8+
# Order is important; the last matching pattern takes the
9+
# most precedence.
10+
# =======================================================
11+
12+
13+
# All of CoreTools PR should have the owners in the PR.
14+
* @michaelpeng36 @AnatoliB
15+
16+
# Adding codeowner for Language specific files such that GitHub automatically adds language owners as a reviewers.
17+
src/Azure.Functions.Cli/Azure.Functions.Cli.csproj @vrdmr @Francisco-Gamino @amamounelsayed @alrod @michaelpeng36 @AnatoliB

azure-pipelines.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: $(Build.SourceBranchName)_$(Build.Reason)_$(devops_buildNumber)
1+
name: $(Build.SourceBranchName)_$(Build.Reason)
22

33
pr:
44
branches:

build/BuildSteps.cs

+44-16
Original file line numberDiff line numberDiff line change
@@ -65,20 +65,10 @@ public static void UpdatePackageVersionForIntegrationTests()
6565

6666
foreach (var package in packagesToUpdate)
6767
{
68-
string packageInfo = Shell.GetOutput("NuGet", $"list {package} -Source {AzureFunctionsPreReleaseFeedName} -prerelease").Split(Environment.NewLine)[0];
68+
var packageInfo = GetLatestPackageInfo(name: package.Name, majorVersion: package.MajorVersion, source: AzureFunctionsPreReleaseFeedName);
69+
Shell.Run("dotnet", $"add package {packageInfo.Name} -v {packageInfo.Version} -s {AzureFunctionsPreReleaseFeedName} --no-restore");
6970

70-
if (string.IsNullOrEmpty(packageInfo))
71-
{
72-
throw new Exception($"Failed to get {package} package information from {AzureFunctionsPreReleaseFeedName}.");
73-
}
74-
75-
var parts = packageInfo.Split(" ");
76-
var packageName = parts[0];
77-
var packageVersion = parts[1];
78-
79-
Shell.Run("dotnet", $"add package {packageName} -v {packageVersion} -s {AzureFunctionsPreReleaseFeedName} --no-restore");
80-
81-
buildPackages.Add(packageName, packageVersion);
71+
buildPackages.Add(packageInfo.Name, packageInfo.Version);
8272
}
8373
}
8474
finally
@@ -624,9 +614,9 @@ public static void CreateIntegrationTestsBuildManifest()
624614
}
625615
}
626616

627-
private static List<string> GetV3PackageList()
617+
private static List<Package> GetV3PackageList()
628618
{
629-
const string CoreToolsBuildPackageList = "https://raw.githubusercontent.com/Azure/azure-functions-integration-tests/dev/integrationTestsBuild/V3/CoreToolsBuild.json";
619+
const string CoreToolsBuildPackageList = "https://raw.githubusercontent.com/Azure/azure-functions-integration-tests/dev/integrationTestsBuild/V3/CoreToolsBuild2.json";
630620
Uri address = new Uri(CoreToolsBuildPackageList);
631621

632622
string content = null;
@@ -640,7 +630,7 @@ private static List<string> GetV3PackageList()
640630
throw new Exception($"Failed to download package list from {CoreToolsBuildPackageList}");
641631
}
642632

643-
var packageList = JsonConvert.DeserializeObject<List<string>>(content);
633+
var packageList = JsonConvert.DeserializeObject<List<Package>>(content);
644634

645635
return packageList;
646636
}
@@ -656,5 +646,43 @@ private static void RemoveLanguageWorkers(string outputPath)
656646
}
657647
}
658648
}
649+
650+
private static PackageInfo GetLatestPackageInfo(string name, string majorVersion, string source)
651+
{
652+
string includeAllVersion = !string.IsNullOrWhiteSpace(majorVersion) ? "-AllVersions" : string.Empty;
653+
string packageInfo = Shell.GetOutput("NuGet", $"list {name} -Source {source} -prerelease {includeAllVersion}");
654+
655+
if (packageInfo.Contains("No packages found", StringComparison.OrdinalIgnoreCase))
656+
{
657+
throw new Exception($"Package name {name} not found in {source}.");
658+
}
659+
660+
if (!string.IsNullOrWhiteSpace(majorVersion))
661+
{
662+
foreach (var package in packageInfo.Split(Environment.NewLine))
663+
{
664+
var thisPackage = NewPackageInfo(package);
665+
if (thisPackage.Name.Equals(name, StringComparison.OrdinalIgnoreCase) && thisPackage.Version.StartsWith(majorVersion))
666+
{
667+
return thisPackage;
668+
}
669+
}
670+
671+
throw new Exception($"Failed to find {name} package for major version {majorVersion}.");
672+
}
673+
674+
return NewPackageInfo(packageInfo);
675+
}
676+
677+
private static PackageInfo NewPackageInfo(string packageInfo)
678+
{
679+
var parts = packageInfo.Split(" ");
680+
if (parts.Length > 2)
681+
{
682+
throw new Exception($"Invalid package format. The string should only contain 'name<space>version'. Current value: '{packageInfo}'");
683+
}
684+
685+
return new PackageInfo(Name: parts[0], Version: parts[1]);
686+
}
659687
}
660688
}

build/Package.cs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Build
6+
{
7+
internal class Package
8+
{
9+
public string Name { get; set; }
10+
public string MajorVersion { get; set; }
11+
}
12+
}

build/PackageInfo.cs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Build
6+
{
7+
internal class PackageInfo
8+
{
9+
public PackageInfo(string Name, string Version)
10+
{
11+
this.Name = Name;
12+
this.Version = Version;
13+
}
14+
15+
public string Name { get; set; }
16+
public string Version { get; set; }
17+
}
18+
}

build/Settings.cs

+5
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,13 @@ public class SignInfo
166166
"DotNetZip.dll",
167167
"Dynamitey.dll",
168168
"Google.Protobuf.dll",
169+
"Grpc.AspNetCore.Server.ClientFactory.dll",
170+
"Grpc.AspNetCore.Server.dll",
169171
"Grpc.Core.dll",
170172
"Grpc.Core.Api.dll",
173+
"Grpc.Net.Client.dll",
174+
"Grpc.Net.ClientFactory.dll",
175+
"Grpc.Net.Common.dll",
171176
"grpc_csharp_ext.x64.dll",
172177
"grpc_csharp_ext.x86.dll",
173178
"HTTPlease.Core.dll",

src/Azure.Functions.Cli/Actions/AzureActions/BaseFunctionAppAction.cs

+7-7
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,22 @@ abstract class BaseFunctionAppAction : BaseAzureAction
1313

1414
public override ICommandLineParserResult ParseArgs(string[] args)
1515
{
16+
Parser
17+
.Setup<string>("slot")
18+
.WithDescription("The deployment slot in the function app to use (if configured)")
19+
.SetDefault(null)
20+
.Callback(t => Slot = t);
21+
1622
if (args.Any() && !args.First().StartsWith("-"))
1723
{
1824
FunctionAppName = args.First();
1925
}
2026
else
2127
{
22-
throw new CliArgumentsException("Must specify functionApp name.", Parser.Parse(args),
28+
throw new CliArgumentsException("Must specify functionApp name.", base.ParseArgs(args),
2329
new CliArgument { Name = nameof(FunctionAppName), Description = "Function App name" });
2430
}
2531

26-
Parser
27-
.Setup<string>("slot")
28-
.WithDescription("The deployment slot in the function app to use (if configured)")
29-
.SetDefault(null)
30-
.Callback(t => Slot = t);
31-
3232
return base.ParseArgs(args);
3333
}
3434
}

src/Azure.Functions.Cli/Actions/AzureActions/PublishFunctionAppAction.cs

+11-3
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ internal class PublishFunctionAppAction : BaseFunctionAppAction
4242
public BuildOption PublishBuildOption { get; set; }
4343
public string AdditionalPackages { get; set; } = string.Empty;
4444
public bool NoBuild { get; set; }
45-
public string DotnetCliParameters { get; set; }
45+
46+
// For .net function apps, build using "release" configuration by default. User can override using "--dotnet-cli-params" as needed.
47+
public string DotnetCliParameters { get; set; } = "--configuration release";
4648
public string DotnetFrameworkVersion { get; set; }
4749

4850
public PublishFunctionAppAction(ISettings settings, ISecretsManager secretsManager)
@@ -107,10 +109,16 @@ public override ICommandLineParserResult ParseArgs(string[] args)
107109
Parser
108110
.Setup<bool>("no-build")
109111
.WithDescription("Skip building and fetching dependencies for the function project.")
110-
.Callback(f => NoBuild = f);
112+
.Callback(f => NoBuild = f);
113+
// Note about usage:
114+
// The value of 'dotnet-cli-params' option should either use a leading space character or escape the double quotes explicitly.
115+
// Ex 1: --dotnet-cli-params " --configuration debug"
116+
// Ex 2: --dotnet-cli-params "\"--configuration debug"\"
117+
// If you don't do this, the value with leading - or -- will be read as a key (rather than the value of 'dotnet-cli-params').
118+
// See https://github.com/fclp/fluent-command-line-parser/issues/99 for reference.
111119
Parser
112120
.Setup<string>("dotnet-cli-params")
113-
.WithDescription("When publishing dotnet functions, the core tools calls 'dotnet build --output bin/publish'. Any parameters passed to this will be appended to the command line.")
121+
.WithDescription("When publishing dotnet functions, the core tools calls 'dotnet build --output bin/publish --configuration release'. Any parameters passed to this will be appended to the command line.")
114122
.Callback(s => DotnetCliParameters = s);
115123
Parser
116124
.Setup<string>("dotnet-version")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
using Microsoft.Azure.WebJobs.Script;
3+
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
4+
using Microsoft.Extensions.DependencyInjection;
5+
6+
namespace Azure.Functions.Cli.Diagnostics
7+
{
8+
internal class DotNetIsolatedDebugConfigureBuilder : IConfigureBuilder<IServiceCollection>
9+
{
10+
public void Configure(IServiceCollection services)
11+
{
12+
services.PostConfigure<LanguageWorkerOptions>(o =>
13+
{
14+
foreach (var workerConfig in o.WorkerConfigs)
15+
{
16+
// We do not want to timeout while debugging.
17+
workerConfig.CountOptions.ProcessStartupTimeout = TimeSpan.FromDays(30);
18+
workerConfig.CountOptions.InitializationTimeout = TimeSpan.FromDays(30);
19+
}
20+
});
21+
}
22+
}
23+
}

src/Azure.Functions.Cli/Actions/HostActions/StartHostAction.cs

+21-18
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,15 @@ private async Task<IWebHost> BuildWebHost(ScriptApplicationHostOptions hostOptio
225225
// This is needed to filter system logs only for known categories
226226
loggingBuilder.AddDefaultWebJobsFilters<ColoredConsoleLoggerProvider>(LogLevel.Trace);
227227
})
228-
.ConfigureServices((context, services) => services.AddSingleton<IStartup>(new Startup(context, hostOptions, CorsOrigins, CorsCredentials, EnableAuth, UserSecretsId, loggingFilterHelper, JsonOutputFile)))
228+
.ConfigureServices((context, services) =>
229+
{
230+
services.AddSingleton<IStartup>(new Startup(context, hostOptions, CorsOrigins, CorsCredentials, EnableAuth, UserSecretsId, loggingFilterHelper, JsonOutputFile));
231+
232+
if (DotNetIsolatedDebug != null && DotNetIsolatedDebug.Value)
233+
{
234+
services.AddSingleton<IConfigureBuilder<IServiceCollection>>(_ => new DotNetIsolatedDebugConfigureBuilder());
235+
}
236+
})
229237
.Build();
230238
}
231239

@@ -325,6 +333,9 @@ public override async Task RunAsync()
325333
// Suppress AspNetCoreSupressStatusMessages
326334
EnvironmentHelper.SetEnvironmentVariableAsBoolIfNotExists(Constants.AspNetCoreSupressStatusMessages);
327335

336+
// Suppress startup logs coming from grpc server startup
337+
Environment.SetEnvironmentVariable("Logging__LogLevel__Microsoft.Hosting.Lifetime", "None");
338+
328339
Utilities.PrintVersion();
329340

330341
ScriptApplicationHostOptions hostOptions = SelfHostWebHostSettingsFactory.Create(Environment.CurrentDirectory);
@@ -415,7 +426,7 @@ private bool IsPreCompiledFunctionApp()
415426
return isPrecompiled;
416427
}
417428

418-
internal static async Task CheckNonOptionalSettings(IEnumerable<KeyValuePair<string, string>> secrets, string scriptPath, bool userSecretsEnabled)
429+
internal static async Task CheckNonOptionalSettings(IEnumerable<KeyValuePair<string, string>> secrets, string scriptPath, bool skipAzureWebJobsStorageCheck = false)
419430
{
420431
string storageConnectionKey = "AzureWebJobsStorage";
421432
try
@@ -441,15 +452,12 @@ internal static async Task CheckNonOptionalSettings(IEnumerable<KeyValuePair<str
441452
.Where(b => b.IndexOf("Trigger", StringComparison.OrdinalIgnoreCase) != -1)
442453
.All(t => Constants.TriggersWithoutStorage.Any(tws => tws.Equals(t, StringComparison.OrdinalIgnoreCase)));
443454

444-
if (string.IsNullOrWhiteSpace(azureWebJobsStorage) &&
445-
!StorageConnectionExists(secrets, storageConnectionKey) &&
446-
!allNonStorageTriggers)
455+
if (!skipAzureWebJobsStorageCheck && string.IsNullOrWhiteSpace(azureWebJobsStorage) &&
456+
!StorageConnectionExists(secrets, storageConnectionKey) && !allNonStorageTriggers)
447457
{
448-
string errorMessage = userSecretsEnabled ? Constants.Errors.WebJobsStorageNotFoundWithUserSecrets : Constants.Errors.WebJobsStorageNotFound;
449-
throw new CliException(string.Format(errorMessage,
450-
SecretsManager.AppSettingsFileName,
451-
string.Join(", ", Constants.TriggersWithoutStorage),
452-
SecretsManager.AppSettingsFileName));
458+
throw new CliException($"Missing value for AzureWebJobsStorage in {SecretsManager.AppSettingsFileName}. " +
459+
$"This is required for all triggers other than {string.Join(", ", Constants.TriggersWithoutStorage)}. "
460+
+ $"You can run 'func azure functionapp fetch-app-settings <functionAppName>', specify a connection string in {SecretsManager.AppSettingsFileName}, or use managed identity to authenticate.");
453461
}
454462

455463
foreach ((var filePath, var functionJson) in functionsJsons)
@@ -467,14 +475,9 @@ internal static async Task CheckNonOptionalSettings(IEnumerable<KeyValuePair<str
467475
}
468476
else if (!secrets.Any(v => v.Key.Equals(appSettingName, StringComparison.OrdinalIgnoreCase)))
469477
{
470-
string warningMessage = userSecretsEnabled ? Constants.Errors.AppSettingNotFoundWithUserSecrets : Constants.Errors.AppSettingNotFound;
471-
ColoredConsole.WriteLine(WarningColor(string.Format(warningMessage,
472-
appSettingName,
473-
SecretsManager.AppSettingsFileName,
474-
token.Key,
475-
binding["type"]?.ToString(),
476-
filePath,
477-
SecretsManager.AppSettingsFileName)));
478+
ColoredConsole
479+
.WriteLine(WarningColor($"Warning: Cannot find value named '{appSettingName}' in {SecretsManager.AppSettingsFileName} that matches '{token.Key}' property set on '{binding["type"]?.ToString()}' in '{filePath}'. " +
480+
$"You can run 'func azure functionapp fetch-app-settings <functionAppName>' or specify a connection string in {SecretsManager.AppSettingsFileName}."));
478481
}
479482
}
480483
}

src/Azure.Functions.Cli/Actions/LocalActions/AddSettingAction.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public override ICommandLineParserResult ParseArgs(string[] args)
3333

3434
if (args.Length == 0)
3535
{
36-
throw new CliArgumentsException("Must specify setting name.", Parser.Parse(args),
36+
throw new CliArgumentsException("Must specify setting name.", base.ParseArgs(args),
3737
new CliArgument { Name = nameof(Name), Description = "App setting name" },
3838
new CliArgument { Name = nameof(Value), Description = "(Optional) App setting value. Omit for secure values."});
3939
}

src/Azure.Functions.Cli/Actions/LocalActions/DeleteSettingAction.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public override ICommandLineParserResult ParseArgs(string[] args)
3030

3131
if (args.Length == 0)
3232
{
33-
throw new CliArgumentsException("Must specify setting name.", Parser.Parse(args),
33+
throw new CliArgumentsException("Must specify setting name.", base.ParseArgs(args),
3434
new CliArgument { Name = nameof(Name), Description = "Name of app setting to be deleted." });
3535
}
3636
else

src/Azure.Functions.Cli/Actions/LocalActions/PackAction.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
namespace Azure.Functions.Cli.Actions.LocalActions
1616
{
17-
[Action(Name = "pack", HelpText = "Pack function app into a zip that's ready to run.", ShowInHelp = false)]
17+
[Action(Name = "pack", HelpText = "Pack function app into a zip that's ready to run.", ShowInHelp = true)]
1818
internal class PackAction : BaseAction
1919
{
2020
private readonly ISecretsManager _secretsManager;
@@ -39,7 +39,7 @@ public override ICommandLineParserResult ParseArgs(string[] args)
3939
Parser
4040
.Setup<bool>("build-native-deps")
4141
.SetDefault(false)
42-
.WithDescription("Skips generating .wheels folder when publishing python function apps.")
42+
.WithDescription("Build python packages in a container image")
4343
.Callback(f => BuildNativeDeps = f);
4444
Parser
4545
.Setup<bool>("no-bundler")

0 commit comments

Comments
 (0)