From 6faf0362397ae881ee06c58c14f524f4d5a04dbb Mon Sep 17 00:00:00 2001 From: Jacob Viau Date: Wed, 9 Oct 2024 11:35:23 -0700 Subject: [PATCH 1/7] Refactor SDK to consume output path from WorkerExtensions.csproj --- sdk/Sdk/ExtensionsMetadata.cs | 4 +- sdk/Sdk/ExtensionsMetadataEnhancer.cs | 60 ++++++ ...crosoft.Azure.Functions.Worker.Sdk.targets | 202 ++++++++++-------- sdk/Sdk/Tasks/EnhanceExtensionsMetadata.cs | 13 +- sdk/Sdk/Tasks/GenerateFunctionMetadata.cs | 18 +- 5 files changed, 202 insertions(+), 95 deletions(-) diff --git a/sdk/Sdk/ExtensionsMetadata.cs b/sdk/Sdk/ExtensionsMetadata.cs index f7ed7912f..cc2588af8 100644 --- a/sdk/Sdk/ExtensionsMetadata.cs +++ b/sdk/Sdk/ExtensionsMetadata.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. using System.Collections.Generic; @@ -9,6 +9,6 @@ namespace Microsoft.Azure.Functions.Worker.Sdk public class ExtensionsMetadata { [JsonPropertyName("extensions")] - public IEnumerable? Extensions { get; set; } + public List Extensions { get; } = new List(); } } diff --git a/sdk/Sdk/ExtensionsMetadataEnhancer.cs b/sdk/Sdk/ExtensionsMetadataEnhancer.cs index 9259dbc70..11266b74a 100644 --- a/sdk/Sdk/ExtensionsMetadataEnhancer.cs +++ b/sdk/Sdk/ExtensionsMetadataEnhancer.cs @@ -2,7 +2,11 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; using System.Text.RegularExpressions; +using Mono.Cecil; namespace Microsoft.Azure.Functions.Worker.Sdk { @@ -25,6 +29,34 @@ public static void AddHintPath(IEnumerable extensions) } } + public static IEnumerable GetWebJobsExtensions(string fileName) + { + // NOTE: this is an incomplete approach to getting extensions and is intended only for our usages. + // Running this with arbitrary assemblies (especially user supplied) can lead to exceptions. + AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(fileName); + IEnumerable attributes = assembly.Modules.SelectMany(p => p.GetCustomAttributes()) + .Where(a => a.AttributeType.FullName == "Microsoft.Azure.WebJobs.Hosting.WebJobsStartupAttribute"); + + foreach (CustomAttribute attribute in attributes) + { + CustomAttributeArgument typeProperty = attribute.ConstructorArguments.ElementAtOrDefault(0); + CustomAttributeArgument nameProperty = attribute.ConstructorArguments.ElementAtOrDefault(1); + + TypeDefinition typeDef = (TypeDefinition)typeProperty.Value; + string assemblyQualifiedName = Assembly.CreateQualifiedName( + typeDef.Module.Assembly.FullName, GetReflectionFullName(typeDef)); + + string name = GetName((string)nameProperty.Value, typeDef); + + yield return new ExtensionReference + { + Name = name, + TypeName = assemblyQualifiedName, + HintPath = $@"{ExtensionsBinaryDirectoryPath}/{Path.GetFileName(fileName)}", + }; + } + } + private static string? GetAssemblyNameOrNull(string? typeName) { if (typeName == null) @@ -41,5 +73,33 @@ public static void AddHintPath(IEnumerable extensions) return null; } + + // Copying the WebJobsStartup constructor logic from: + // https://github.com/Azure/azure-webjobs-sdk/blob/e5417775bcb8c8d3d53698932ca8e4e265eac66d/src/Microsoft.Azure.WebJobs.Host/Hosting/WebJobsStartupAttribute.cs#L33-L47. + private static string GetName(string name, TypeDefinition startupTypeDef) + { + if (string.IsNullOrEmpty(name)) + { + // for a startup class named 'CustomConfigWebJobsStartup' or 'CustomConfigStartup', + // default to a name 'CustomConfig' + name = startupTypeDef.Name; + int idx = name.IndexOf("WebJobsStartup"); + if (idx < 0) + { + idx = name.IndexOf("Startup"); + } + if (idx > 0) + { + name = name.Substring(0, idx); + } + } + + return name; + } + + private static string GetReflectionFullName(TypeReference typeRef) + { + return typeRef.FullName.Replace("/", "+"); + } } } diff --git a/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets b/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets index a5389f5c7..ed301adee 100644 --- a/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets +++ b/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets @@ -10,30 +10,39 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and --> + + + <_FunctionsTaskFramework Condition="'$(MSBuildRuntimeType)' == 'Core'">netstandard2.0 + <_FunctionsTaskFramework Condition="'$(_FunctionsTaskFramework)' == ''">net472 + <_FunctionsTasksDir Condition="'$(_FunctionsTasksDir)'==''">$(MSBuildThisFileDirectory)..\tools\$(_FunctionsTaskFramework)\ + <_FunctionsTaskAssemblyFullPath Condition=" '$(_FunctionsTaskAssemblyFullPath)'=='' ">$(_FunctionsTasksDir)\Microsoft.Azure.Functions.Worker.Sdk.dll + $(MSBuildExtensionsPath)\Microsoft\VisualStudio\Managed.Functions\ + + + + + true + <_FunctionsExtensionsDirectory>.azurefunctions + <_FunctionsExtensionsJsonName>extensions.json + <_FunctionsWorkerConfigInputFile>$(MSBuildThisFileDirectory)\..\tools\worker.config.json + <_FunctionsMetadataLoaderExtensionFile>$(MSBuildThisFileDirectory)\..\tools\netstandard2.0\Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.dll + <_FunctionsExtensionCommonProps>ImportDirectoryBuildProps=false;ImportDirectoryBuildTargets=false;ImportDirectoryPackagesProps=false + <_FunctionsExtensionRemoveProps>TargetFramework;RuntimeIdentifier;SelfContained;PublishSingleFile;PublishReadyToRun;UseCurrentRuntimeIdentifier;WebPublishMethod;PublishProfile;DeployOnBuild;PublishDir + + + - <_ToolingSuffix> <_DefaultAzureFunctionsVersion>v4 <_AzureFunctionsVersionNotSet Condition="'$(AzureFunctionsVersion)' == ''">true $(_DefaultAzureFunctionsVersion) + true + <_ToolingSuffix Condition="($(AzureFunctionsVersion.StartsWith('v3',StringComparison.OrdinalIgnoreCase)) Or $(AzureFunctionsVersion.StartsWith('v4',StringComparison.OrdinalIgnoreCase))) And '$(TargetFrameworkIdentifier)' == '.NETCoreApp' And '$(TargetFrameworkVersion)' == 'v5.0'">net5-isolated <_ToolingSuffix Condition="$(AzureFunctionsVersion.StartsWith('v4',StringComparison.OrdinalIgnoreCase)) And '$(TargetFrameworkIdentifier)' == '.NETCoreApp' And '$(TargetFrameworkVersion)' == 'v6.0'">net6-isolated <_ToolingSuffix Condition="$(AzureFunctionsVersion.StartsWith('v4',StringComparison.OrdinalIgnoreCase)) And '$(TargetFrameworkIdentifier)' == '.NETCoreApp' And '$(TargetFrameworkVersion)' == 'v7.0'">net7-isolated <_ToolingSuffix Condition="$(AzureFunctionsVersion.StartsWith('v4',StringComparison.OrdinalIgnoreCase)) And '$(TargetFrameworkIdentifier)' == '.NETCoreApp' And '$(TargetFrameworkVersion)' == 'v8.0'">net8-isolated <_ToolingSuffix Condition="$(AzureFunctionsVersion.StartsWith('v4',StringComparison.OrdinalIgnoreCase)) And '$(TargetFrameworkIdentifier)' == '.NETFramework'">netfx-isolated $(_ToolingSuffix) - <_FunctionsTaskFramework Condition="'$(MSBuildRuntimeType)' == 'Core'">netstandard2.0 - <_FunctionsTaskFramework Condition="'$(_FunctionsTaskFramework)' == ''">net472 - <_FunctionsTasksDir Condition="'$(_FunctionsTasksDir)'==''">$(MSBuildThisFileDirectory)..\tools\$(_FunctionsTaskFramework)\ - <_FunctionsTaskAssemblyFullPath Condition=" '$(_FunctionsTaskAssemblyFullPath)'=='' ">$(_FunctionsTasksDir)\Microsoft.Azure.Functions.Worker.Sdk.dll - - <_FunctionsExtensionCommonProps>ImportDirectoryBuildProps=false;ImportDirectoryBuildTargets=false;ImportDirectoryPackagesProps=false - <_FunctionsExtensionRemoveProps>TargetFramework;Platform;RuntimeIdentifier;SelfContained;PublishSingleFile;PublishReadyToRun;UseCurrentRuntimeIdentifier;WebPublishMethod;PublishProfile;DeployOnBuild;PublishDir - <_FunctionsWorkerConfigInputFile>$(MSBuildThisFileDirectory)\..\tools\worker.config.json - - <_FunctionsMetadataLoaderExtensionFile>$(MSBuildThisFileDirectory)\..\tools\netstandard2.0\Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.dll - <_FunctionsExtensionsDirectory>.azurefunctions - <_FunctionsExtensionsJsonName>extensions.json - $(MSBuildExtensionsPath)\Microsoft\VisualStudio\Managed.Functions\ false true @@ -43,13 +52,13 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and true true - <_FunctionsGenerateExtensionProject Condition="'$(DesignTimeBuild)' != 'true'">true + <_FunctionsBuildEnabled Condition="'$(DesignTimeBuild)' != 'true'">true $(RootNamespace.Replace("-", "_")) <_FunctionsVersion Include="v3" InSupport="false" /> - <_FunctionsVersion Include="$(_DefaultAzureFunctionsVersion)" InSupport="true" /> + <_FunctionsVersion Include="v4" InSupport="true" /> @@ -60,88 +69,110 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and + + + $([System.IO.Path]::GetDirectoryName($(ExtensionsCsProj))) + $(IntermediateOutputPath)WorkerExtensions + $([System.IO.Path]::GetFullPath($(ExtensionsCsProjDirectory))) + $([System.IO.Path]::Combine($(ExtensionsCsProjDirectory), WorkerExtensions.csproj)) + + + + <_FunctionsMetadataPath>$(IntermediateOutputPath)functions.metadata + <_FunctionsWorkerConfigPath>$(IntermediateOutputPath)worker.config.json + + + - + <_AzureFunctionsVersionStandardized>$(AzureFunctionsVersion.ToLowerInvariant().Split('-')[0]) - true <_SelectedFunctionVersion Include="@(_FunctionsVersion)" Condition="'%(_FunctionsVersion.Identity)' == '$(_AzureFunctionsVersionStandardized)'" /> + + + + + + - - + + - + + + + DependsOnTargets="_WorkerExtensionsRestore;_WorkerExtensionsBuild" /> - - + + + + - - + + - <_FunctionsMetadataPath>$(IntermediateOutputPath)functions.metadata - <_FunctionsWorkerConfigPath>$(IntermediateOutputPath)worker.config.json - $(IntermediateOutputPath)WorkerExtensions - $([System.IO.Path]::GetFullPath($(ExtensionsCsProjDirectory))) - $([System.IO.Path]::Combine($(ExtensionsCsProjDirectory), WorkerExtensions.csproj)) - <_FunctionsIntermediateExtensionJsonPath>$(ExtensionsCsProjDirectory)\buildout\bin\$(_FunctionsExtensionsJsonName) + <_WorkerExtensionTarget>Build + <_WorkerExtensionTarget Condition="'$(FunctionsGenerateExtensionProject)' == 'false'">GetTargetPath + <_WorkerExtensionProperties Condition="'$(FunctionsGenerateExtensionProject)' == 'true'">Configuration=Release;$(_FunctionsExtensionCommonProps) + + + + + + + + <_FunctionsExtensionsOutputPath>$([System.IO.Path]::GetDirectoryName($(_WorkerExtensionsAssembly))) + <_FunctionsIntermediateExtensionJsonPath>$(_FunctionsExtensionsOutputPath)/bin/$(_FunctionsExtensionsJsonName) <_FunctionsIntermediateExtensionUpdatedJsonPath>$(IntermediateOutputPath)$(_FunctionsExtensionsJsonName) - - - - - - - - + + + DependsOnTargets="_FunctionsGenerateCommon;_FunctionsGenerateWorkerConfig" /> + + + <_TargetExtensionsCsProj Condition="'$(FunctionsGenerateExtensionProject)' == 'true'">$(ExtensionsCsProj) + + - - - - - @@ -161,27 +192,12 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and Overwrite="true" /> - - - - - - - - - - - + + OutputPath="$(_FunctionsIntermediateExtensionUpdatedJsonPath)" + AdditionalExtensions="$(_FunctionsMetadataLoaderExtensionFile)" /> - <_ExtensionBinaries Include="$(ExtensionsCsProjDirectory)\buildout\bin\**" - Exclude="$(ExtensionsCsProjDirectory)\buildout\bin\runtimes\**;$(_FunctionsIntermediateExtensionJsonPath)" - CopyToOutputDirectory="PreserveNewest" - CopyToPublishDirectory="PreserveNewest" /> - <_ExtensionRuntimeBinaries Include="$(ExtensionsCsProjDirectory)\buildout\runtimes\**" - CopyToOutputDirectory="PreserveNewest" - CopyToPublishDirectory="PreserveNewest" /> + <_ExtensionBinaries Include="$(_FunctionsExtensionsOutputPath)\bin\**" + Exclude="$(_FunctionsExtensionsOutputPath)\bin\runtimes\**;$(_FunctionsIntermediateExtensionJsonPath)" /> + <_ExtensionRuntimeBinaries Include="$(_FunctionsExtensionsOutputPath)\runtimes\**" /> - + - + - <_NoneWithTargetPath Include="@(_ExtensionFilesWithTargetPath)" TargetPath="$(_FunctionsExtensionsDirectory)/%(_ExtensionFilesWithTargetPath.TargetPath)" /> + <_FunctionsAdditionalFile Include="$(_FunctionsMetadataPath);$(_FunctionsWorkerConfigPath);$(_FunctionsIntermediateExtensionUpdatedJsonPath)" /> + <_FunctionsAdditionalFile Include="$(_FunctionsMetadataLoaderExtensionFile)" SubPath="$(_FunctionsExtensionsDirectory)/" /> + <_NoneWithTargetPath Include="@(_FunctionsAdditionalFile)" + TargetPath="%(_FunctionsAdditionalFile.SubPath)%(Filename)%(Extension)" + CopyToOutputDirectory="PreserveNewest" + CopyToPublishDirectory="PreserveNewest"/> + <_NoneWithTargetPath Include="@(_ExtensionFilesWithTargetPath)" + TargetPath="$(_FunctionsExtensionsDirectory)/%(_ExtensionFilesWithTargetPath.TargetPath)" + CopyToOutputDirectory="PreserveNewest" + CopyToPublishDirectory="PreserveNewest"/> - <_WorkerExtFilesToClean Include="$(ExtensionsCsProjDirectory)\**" Condition="'$(ExtensionsCsProjDirectory)' != ''" /> - <_WorkerExtFilesToClean Include="$(TargetDir)$(_FunctionsExtensionsDirectory)\**" /> + <_WorkerExtFilesToClean Include="$(ExtensionsCsProjDirectory)/**" Condition="'$(ExtensionsCsProjDirectory)' != '' AND '$(FunctionsGenerateExtensionProject)' == 'true'" /> + <_WorkerExtFilesToClean Include="$(TargetDir)$(_FunctionsExtensionsDirectory)/**" /> <_WorkerExtFilesToClean Include="$(_FunctionsMetadataPath)" /> <_WorkerExtFilesToClean Include="$(_FunctionsWorkerConfigPath)" /> <_WorkerExtFilesToClean Include="$(TargetDir)worker.config.json" /> @@ -229,10 +250,19 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and - + + + + + + + + + true + - \ No newline at end of file + diff --git a/sdk/Sdk/Tasks/EnhanceExtensionsMetadata.cs b/sdk/Sdk/Tasks/EnhanceExtensionsMetadata.cs index c76bb4871..fa73090a9 100644 --- a/sdk/Sdk/Tasks/EnhanceExtensionsMetadata.cs +++ b/sdk/Sdk/Tasks/EnhanceExtensionsMetadata.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.Json; @@ -24,12 +25,20 @@ public class EnhanceExtensionsMetadata : Task [Required] public string? OutputPath { get; set; } + [Required] + public ITaskItem[]? AdditionalExtensions { get; set; } + public override bool Execute() { string json = File.ReadAllText(ExtensionsJsonPath); - var extensionsMetadata = JsonSerializer.Deserialize(json); - ExtensionsMetadataEnhancer.AddHintPath(extensionsMetadata?.Extensions ?? Enumerable.Empty()); + var extensionsMetadata = JsonSerializer.Deserialize(json) ?? new ExtensionsMetadata(); + ExtensionsMetadataEnhancer.AddHintPath(extensionsMetadata.Extensions); + + foreach (ITaskItem item in AdditionalExtensions ?? Enumerable.Empty()) + { + extensionsMetadata.Extensions.AddRange(ExtensionsMetadataEnhancer.GetWebJobsExtensions(item.ItemSpec)); + } string newJson = JsonSerializer.Serialize(extensionsMetadata, _serializerOptions); File.WriteAllText(OutputPath, newJson); diff --git a/sdk/Sdk/Tasks/GenerateFunctionMetadata.cs b/sdk/Sdk/Tasks/GenerateFunctionMetadata.cs index e8e42cee2..752707582 100644 --- a/sdk/Sdk/Tasks/GenerateFunctionMetadata.cs +++ b/sdk/Sdk/Tasks/GenerateFunctionMetadata.cs @@ -45,13 +45,21 @@ public override bool Execute() { var functionGenerator = new FunctionMetadataGenerator(MSBuildLogger); - var functions = functionGenerator.GenerateFunctionMetadata(AssemblyPath!, ReferencePaths ?? Enumerable.Empty()); + IEnumerable functions = functionGenerator.GenerateFunctionMetadata(AssemblyPath!, ReferencePaths ?? Enumerable.Empty()); + IDictionary extensions = functionGenerator.Extensions; - var extensions = functionGenerator.Extensions; - var extensionsCsProjGenerator = new ExtensionsCsprojGenerator(extensions, ExtensionsCsProjFilePath!, AzureFunctionsVersion!, TargetFrameworkIdentifier!, TargetFrameworkVersion!); + if (!string.IsNullOrEmpty(ExtensionsCsProjFilePath)) + { + // Null/empty ExtensionsCsProjFilePath means the extension project is externally provided. + var extensionsCsProjGenerator = new ExtensionsCsprojGenerator(extensions, ExtensionsCsProjFilePath!, AzureFunctionsVersion!, TargetFrameworkIdentifier!, TargetFrameworkVersion!); + extensionsCsProjGenerator.Generate(); + } - extensionsCsProjGenerator.Generate(); - WriteMetadataWithRetry(functions); + if (!string.IsNullOrEmpty(OutputPath)) + { + // Null/empty OutputPath means we do not want to write the metadata, typically when we are one-off generating the extension csproj. + WriteMetadataWithRetry(functions); + } } catch (FunctionsMetadataGenerationException) { From 4241df2be57b0a4abca0ebc4e2013456f204e5b4 Mon Sep 17 00:00:00 2001 From: Jacob Viau Date: Wed, 9 Oct 2024 11:32:06 -0700 Subject: [PATCH 2/7] Allow for extension project to be externally supplied --- sdk/Sdk/ExtensionsCsprojGenerator.cs | 14 +++++--------- sdk/Sdk/Tasks/GenerateFunctionMetadata.cs | 7 +------ .../ExtensionsCsProjGeneratorTests.cs | 15 +++++++-------- 3 files changed, 13 insertions(+), 23 deletions(-) diff --git a/sdk/Sdk/ExtensionsCsprojGenerator.cs b/sdk/Sdk/ExtensionsCsprojGenerator.cs index b8ba95584..81e7d0c5e 100644 --- a/sdk/Sdk/ExtensionsCsprojGenerator.cs +++ b/sdk/Sdk/ExtensionsCsprojGenerator.cs @@ -10,8 +10,6 @@ namespace Microsoft.Azure.Functions.Worker.Sdk { internal class ExtensionsCsprojGenerator { - internal const string ExtensionsProjectName = "WorkerExtensions.csproj"; - private readonly IDictionary _extensions; private readonly string _outputPath; private readonly string _targetFrameworkIdentifier; @@ -29,22 +27,20 @@ public ExtensionsCsprojGenerator(IDictionary extensions, string public void Generate() { - var extensionsCsprojFilePath = Path.Combine(_outputPath, ExtensionsProjectName); - string csproj = GetCsProjContent(); - if (File.Exists(extensionsCsprojFilePath)) + if (File.Exists(_outputPath)) { - string existing = File.ReadAllText(extensionsCsprojFilePath); + string existing = File.ReadAllText(_outputPath); if (string.Equals(csproj, existing, StringComparison.Ordinal)) { // If contents are the same, only touch the file to update timestamp. - File.SetLastWriteTimeUtc(extensionsCsprojFilePath, DateTime.UtcNow); + File.SetLastWriteTimeUtc(_outputPath, DateTime.UtcNow); return; } } - RecreateDirectory(_outputPath); - File.WriteAllText(extensionsCsprojFilePath, csproj); + RecreateDirectory(Path.GetDirectoryName(_outputPath)); + File.WriteAllText(_outputPath, csproj); } private void RecreateDirectory(string directoryPath) diff --git a/sdk/Sdk/Tasks/GenerateFunctionMetadata.cs b/sdk/Sdk/Tasks/GenerateFunctionMetadata.cs index 752707582..e54aa995a 100644 --- a/sdk/Sdk/Tasks/GenerateFunctionMetadata.cs +++ b/sdk/Sdk/Tasks/GenerateFunctionMetadata.cs @@ -24,7 +24,6 @@ public class GenerateFunctionMetadata : Task [Required] public string? OutputPath { get; set; } - [Required] public string? ExtensionsCsProjFilePath { get; set; } [Required] @@ -55,11 +54,7 @@ public override bool Execute() extensionsCsProjGenerator.Generate(); } - if (!string.IsNullOrEmpty(OutputPath)) - { - // Null/empty OutputPath means we do not want to write the metadata, typically when we are one-off generating the extension csproj. - WriteMetadataWithRetry(functions); - } + WriteMetadataWithRetry(functions); } catch (FunctionsMetadataGenerationException) { diff --git a/test/FunctionMetadataGeneratorTests/ExtensionsCsProjGeneratorTests.cs b/test/FunctionMetadataGeneratorTests/ExtensionsCsProjGeneratorTests.cs index 6576e99d7..16d269f97 100644 --- a/test/FunctionMetadataGeneratorTests/ExtensionsCsProjGeneratorTests.cs +++ b/test/FunctionMetadataGeneratorTests/ExtensionsCsProjGeneratorTests.cs @@ -33,20 +33,19 @@ public void GetCsProjContent_Succeeds(FuncVersion version) [InlineData(FuncVersion.V4)] public void GetCsProjContent_IncrementalSupport(FuncVersion version) { - DateTime RunGenerate(string subPath, out string contents) + DateTime RunGenerate(string project, out string contents) { - var generator = GetGenerator(version, subPath); + var generator = GetGenerator(version, project); generator.Generate(); - string path = Path.Combine(subPath, ExtensionsCsprojGenerator.ExtensionsProjectName); - contents = File.ReadAllText(path); - var csproj = new FileInfo(Path.Combine(subPath, ExtensionsCsprojGenerator.ExtensionsProjectName)); + contents = File.ReadAllText(project); + var csproj = new FileInfo(project); return csproj.LastWriteTimeUtc; } - string subPath = Guid.NewGuid().ToString(); - DateTime firstRun = RunGenerate(subPath, out string first); - DateTime secondRun = RunGenerate(subPath, out string second); + string project = Path.Combine(Guid.NewGuid().ToString(), "TestExtension.csproj"); + DateTime firstRun = RunGenerate(project, out string first); + DateTime secondRun = RunGenerate(project, out string second); Assert.NotEqual(firstRun, secondRun); Assert.Equal(first, second); From 49a8115930ff129e82d6907ebd2f42787867646f Mon Sep 17 00:00:00 2001 From: Jacob Viau Date: Thu, 10 Oct 2024 16:19:50 -0700 Subject: [PATCH 3/7] Fix JSON deserialization --- sdk/Sdk/ExtensionsMetadata.cs | 2 +- sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/Sdk/ExtensionsMetadata.cs b/sdk/Sdk/ExtensionsMetadata.cs index cc2588af8..2fcd1ae18 100644 --- a/sdk/Sdk/ExtensionsMetadata.cs +++ b/sdk/Sdk/ExtensionsMetadata.cs @@ -9,6 +9,6 @@ namespace Microsoft.Azure.Functions.Worker.Sdk public class ExtensionsMetadata { [JsonPropertyName("extensions")] - public List Extensions { get; } = new List(); + public List Extensions { get; set; } = new List(); } } diff --git a/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets b/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets index ed301adee..ad043a858 100644 --- a/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets +++ b/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets @@ -24,8 +24,8 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and true <_FunctionsExtensionsDirectory>.azurefunctions <_FunctionsExtensionsJsonName>extensions.json - <_FunctionsWorkerConfigInputFile>$(MSBuildThisFileDirectory)\..\tools\worker.config.json - <_FunctionsMetadataLoaderExtensionFile>$(MSBuildThisFileDirectory)\..\tools\netstandard2.0\Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.dll + <_FunctionsWorkerConfigInputFile>$([MSBuild]::NormalizePath($(MSBuildThisFileDirectory)\..\tools\worker.config.json)) + <_FunctionsMetadataLoaderExtensionFile>$([MSBuild]::NormalizePath($(MSBuildThisFileDirectory)\..\tools\netstandard2.0\Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.dll)) <_FunctionsExtensionCommonProps>ImportDirectoryBuildProps=false;ImportDirectoryBuildTargets=false;ImportDirectoryPackagesProps=false <_FunctionsExtensionRemoveProps>TargetFramework;RuntimeIdentifier;SelfContained;PublishSingleFile;PublishReadyToRun;UseCurrentRuntimeIdentifier;WebPublishMethod;PublishProfile;DeployOnBuild;PublishDir From e27e370e2a41b1b6ebf92ca5e30194866d8ff71f Mon Sep 17 00:00:00 2001 From: Jacob Viau Date: Tue, 29 Oct 2024 16:05:28 -0700 Subject: [PATCH 4/7] Update unit test for order --- test/SdkE2ETests/PublishTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/SdkE2ETests/PublishTests.cs b/test/SdkE2ETests/PublishTests.cs index cee2b00a9..072d134dd 100644 --- a/test/SdkE2ETests/PublishTests.cs +++ b/test/SdkE2ETests/PublishTests.cs @@ -60,15 +60,15 @@ private async Task RunPublishTest(string outputDir, string additionalParams = nu { extensions = new[] { - new Extension("Startup", - "Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.Startup, Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader, Version=1.0.0.0, Culture=neutral, PublicKeyToken=551316b6919f366c", - @"./.azurefunctions/Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.dll"), new Extension("AzureStorageBlobs", "Microsoft.Azure.WebJobs.Extensions.Storage.AzureStorageBlobsWebJobsStartup, Microsoft.Azure.WebJobs.Extensions.Storage.Blobs, Version=5.3.1.0, Culture=neutral, PublicKeyToken=92742159e12e44c8", @"./.azurefunctions/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.dll"), new Extension("AzureStorageQueues", "Microsoft.Azure.WebJobs.Extensions.Storage.AzureStorageQueuesWebJobsStartup, Microsoft.Azure.WebJobs.Extensions.Storage.Queues, Version=5.3.1.0, Culture=neutral, PublicKeyToken=92742159e12e44c8", - @"./.azurefunctions/Microsoft.Azure.WebJobs.Extensions.Storage.Queues.dll") + @"./.azurefunctions/Microsoft.Azure.WebJobs.Extensions.Storage.Queues.dll"), + new Extension("Startup", + "Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.Startup, Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader, Version=1.0.0.0, Culture=neutral, PublicKeyToken=551316b6919f366c", + @"./.azurefunctions/Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.dll"), } }); Assert.True(JToken.DeepEquals(extensionsJsonContents, expected), $"Actual: {extensionsJsonContents}{Environment.NewLine}Expected: {expected}"); From 383c6d90a6d2a10539f2532f99bb5a60711410dc Mon Sep 17 00:00:00 2001 From: Jacob Viau Date: Thu, 14 Nov 2024 15:45:29 -0800 Subject: [PATCH 5/7] Fix PublishTests --- samples/FunctionApp/FunctionApp.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/FunctionApp/FunctionApp.csproj b/samples/FunctionApp/FunctionApp.csproj index e0c363aa4..0683410bf 100644 --- a/samples/FunctionApp/FunctionApp.csproj +++ b/samples/FunctionApp/FunctionApp.csproj @@ -9,7 +9,7 @@ - + From fd4ff7944ad178086971b4f520499cadd6995757 Mon Sep 17 00:00:00 2001 From: Jacob Viau Date: Thu, 14 Nov 2024 15:54:12 -0800 Subject: [PATCH 6/7] Fix InnerBuildTests --- test/SdkE2ETests/InnerBuildTests.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/SdkE2ETests/InnerBuildTests.cs b/test/SdkE2ETests/InnerBuildTests.cs index 1f993bd24..3d271f99b 100644 --- a/test/SdkE2ETests/InnerBuildTests.cs +++ b/test/SdkE2ETests/InnerBuildTests.cs @@ -33,11 +33,6 @@ public async Task Build_ScansReferences() JToken extensionsJsonContents = JObject.Parse(File.ReadAllText(extensionsJsonPath)); JToken expectedExtensionsJson = JObject.Parse(@"{ ""extensions"": [ - { - ""name"": ""Startup"", - ""typeName"": ""Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.Startup, Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader, Version=1.0.0.0, Culture=neutral, PublicKeyToken=551316b6919f366c"", - ""hintPath"": ""./.azurefunctions/Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.dll"" - }, { ""name"": ""AzureStorageBlobs"", ""typeName"": ""Microsoft.Azure.WebJobs.Extensions.Storage.AzureStorageBlobsWebJobsStartup, Microsoft.Azure.WebJobs.Extensions.Storage.Blobs, Version=5.3.1.0, Culture=neutral, PublicKeyToken=92742159e12e44c8"", @@ -47,7 +42,12 @@ public async Task Build_ScansReferences() ""name"": ""AzureStorageQueues"", ""typeName"": ""Microsoft.Azure.WebJobs.Extensions.Storage.AzureStorageQueuesWebJobsStartup, Microsoft.Azure.WebJobs.Extensions.Storage.Queues, Version=5.1.3.0, Culture=neutral, PublicKeyToken=92742159e12e44c8"", ""hintPath"": ""./.azurefunctions/Microsoft.Azure.WebJobs.Extensions.Storage.Queues.dll"" - } + }, + { + ""name"": ""Startup"", + ""typeName"": ""Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.Startup, Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader, Version=1.0.0.0, Culture=neutral, PublicKeyToken=551316b6919f366c"", + ""hintPath"": ""./.azurefunctions/Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.dll"" + }, ] }"); From b798be22df3e003e6d23232d19031976f70ef08f Mon Sep 17 00:00:00 2001 From: Jacob Viau Date: Thu, 5 Dec 2024 10:16:42 -0800 Subject: [PATCH 7/7] Suppress OutDir and OutputPath from inner build --- sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets b/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets index b42eeeaa5..5b057d1b6 100644 --- a/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets +++ b/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets @@ -27,7 +27,7 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and <_FunctionsWorkerConfigInputFile>$([MSBuild]::NormalizePath($(MSBuildThisFileDirectory)\..\tools\worker.config.json)) <_FunctionsMetadataLoaderExtensionFile>$([MSBuild]::NormalizePath($(MSBuildThisFileDirectory)\..\tools\netstandard2.0\Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.dll)) <_FunctionsExtensionCommonProps>ImportDirectoryBuildProps=false;ImportDirectoryBuildTargets=false;ImportDirectoryPackagesProps=false - <_FunctionsExtensionRemoveProps>TargetFramework;RuntimeIdentifier;SelfContained;PublishSingleFile;PublishReadyToRun;UseCurrentRuntimeIdentifier;WebPublishMethod;PublishProfile;DeployOnBuild;PublishDir + <_FunctionsExtensionRemoveProps>TargetFramework;RuntimeIdentifier;SelfContained;PublishSingleFile;PublishReadyToRun;UseCurrentRuntimeIdentifier;WebPublishMethod;PublishProfile;DeployOnBuild;PublishDir;OutDir;OutputPath;