Skip to content

Commit 20cc866

Browse files
Scan all .deps.json files and determine root project (#217)
1 parent 6520c5f commit 20cc866

File tree

8 files changed

+126
-17
lines changed

8 files changed

+126
-17
lines changed

src/Microsoft.Azure.Functions.Worker.Extensions.OpenApi/OpenApiHttpTriggerContext.cs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Diagnostics.CodeAnalysis;
34
using System.IO;
45
using System.Linq;
@@ -235,27 +236,44 @@ private string GetRuntimePath(string functionAppDirectory, bool appendBin)
235236
// This method relies on the dependency manifest file to find the function app runtime dll file.
236237
// It can be either <your_runtime>.deps.json or function.deps.json. In most cases, at least the
237238
// function.deps.json should exist, but in case no manifest exists, it will throw the exception.
239+
// In case there are multiple .deps.json files, the root project will be picked, based on the
240+
// dependencies mentioned in the .deps.json files.
238241
private async Task<string> GetRuntimeFilenameAsync(string functionAppDirectory)
239242
{
240243
var files = Directory.GetFiles(functionAppDirectory, "*.deps.json", SearchOption.AllDirectories);
241-
var file = files.FirstOrDefault();
242-
if (file.IsNullOrWhiteSpace())
244+
if (!files.Any())
243245
{
244246
throw new InvalidOperationException("Invalid function app directory");
245247
}
246248

249+
var dependencyManifests = new List<DependencyManifest>();
250+
foreach (var file in files)
251+
{
252+
dependencyManifests.Add(await GetDependencyManifestAsync(file));
253+
}
254+
255+
var runtimes = dependencyManifests
256+
.Select(manifest => manifest.Targets[manifest.RuntimeTarget.Name].First())
257+
.Select(target => new
258+
{
259+
Name = target.Key.Split('/').First(),
260+
FileName = target.Value.Runtime.First().Key,
261+
Dependencies = target.Value.Dependencies.Keys
262+
});
263+
264+
var referencedRuntimes = runtimes.SelectMany(d => d.Dependencies);
265+
return runtimes.FirstOrDefault(r => !referencedRuntimes.Contains(r.Name))?.FileName;
266+
}
267+
268+
private static async Task<DependencyManifest> GetDependencyManifestAsync(string file)
269+
{
247270
var serialised = default(string);
248271
using (var reader = File.OpenText(file))
249272
{
250273
serialised = await reader.ReadToEndAsync();
251274
}
252275

253-
var manifesto = JsonConvert.DeserializeObject<DependencyManifest>(serialised);
254-
var runtimeTarget = manifesto.RuntimeTarget.Name;
255-
var runtimes = manifesto.Targets[runtimeTarget].Values;
256-
var runtime = runtimes.First().Runtime.First().Key;
257-
258-
return runtime;
276+
return JsonConvert.DeserializeObject<DependencyManifest>(serialised);
259277
}
260278

261279
private Assembly GetAssembly(object instance)

src/Microsoft.Azure.WebJobs.Extensions.OpenApi/OpenApiHttpTriggerContext.cs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Diagnostics.CodeAnalysis;
34
using System.IO;
45
using System.Linq;
56
using System.Reflection;
67
using System.Threading.Tasks;
78

8-
using Microsoft.Azure.WebJobs.Extensions.Http;
99
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core;
1010
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions;
1111
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Configurations;
@@ -236,27 +236,44 @@ private string GetRuntimePath(string functionAppDirectory, bool appendBin)
236236
// This method relies on the dependency manifest file to find the function app runtime dll file.
237237
// It can be either <your_runtime>.deps.json or function.deps.json. In most cases, at least the
238238
// function.deps.json should exist, but in case no manifest exists, it will throw the exception.
239+
// In case there are multiple .deps.json files, the root project will be picked, based on the
240+
// dependencies mentioned in the .deps.json files.
239241
private async Task<string> GetRuntimeFilenameAsync(string functionAppDirectory)
240242
{
241243
var files = Directory.GetFiles(functionAppDirectory, "*.deps.json", SearchOption.AllDirectories);
242-
var file = files.FirstOrDefault();
243-
if (file.IsNullOrWhiteSpace())
244+
if (!files.Any())
244245
{
245246
throw new InvalidOperationException("Invalid function app directory");
246247
}
247248

249+
var dependencyManifests = new List<DependencyManifest>();
250+
foreach (var file in files)
251+
{
252+
dependencyManifests.Add(await GetDependencyManifestAsync(file));
253+
}
254+
255+
var runtimes = dependencyManifests
256+
.Select(manifest => manifest.Targets[manifest.RuntimeTarget.Name].First())
257+
.Select(target => new
258+
{
259+
Name = target.Key.Split('/').First(),
260+
FileName = target.Value.Runtime.First().Key,
261+
Dependencies = target.Value.Dependencies.Keys
262+
});
263+
264+
var referencedRuntimes = runtimes.SelectMany(d => d.Dependencies);
265+
return runtimes.FirstOrDefault(r => !referencedRuntimes.Contains(r.Name))?.FileName;
266+
}
267+
268+
private static async Task<DependencyManifest> GetDependencyManifestAsync(string file)
269+
{
248270
var serialised = default(string);
249271
using (var reader = File.OpenText(file))
250272
{
251273
serialised = await reader.ReadToEndAsync();
252274
}
253275

254-
var manifesto = JsonConvert.DeserializeObject<DependencyManifest>(serialised);
255-
var runtimeTarget = manifesto.RuntimeTarget.Name;
256-
var runtimes = manifesto.Targets[runtimeTarget].Values;
257-
var runtime = runtimes.First().Runtime.First().Key;
258-
259-
return runtime;
276+
return JsonConvert.DeserializeObject<DependencyManifest>(serialised);
260277
}
261278

262279
private Assembly GetAssembly(object instance)

test/Microsoft.Azure.Functions.Worker.Extensions.OpenApi.Tests/Microsoft.Azure.Functions.Worker.Extensions.OpenApi.Tests.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
<None Update="local.settings.json">
3737
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
3838
</None>
39+
<None Include="TestData\FakeDependencyFile.deps.json" Link="\%(Filename)%(Extension)">
40+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
41+
</None>
3942
</ItemGroup>
4043

4144
</Project>

test/Microsoft.Azure.Functions.Worker.Extensions.OpenApi.Tests/OpenApiHttpTriggerContextTests.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,18 @@ public async Task Given_Type_When_Initiated_Then_It_Should_Return_ApplicationAss
3131
assembly.DefinedTypes.Select(p => p.FullName).Should().Contain(ti.FullName);
3232
}
3333

34+
[TestMethod]
35+
public async Task Given_Type_With_Referenced_Project_When_Initiated_Then_It_Should_Return_ApplicationAssemblyOfRootAssembly()
36+
{
37+
var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
38+
var context = new OpenApiHttpTriggerContext();
39+
40+
var assembly = (await context.SetApplicationAssemblyAsync(location, false))
41+
.ApplicationAssembly;
42+
43+
assembly.FullName.Should().Be(typeof(OpenApiHttpTriggerContextTests).Assembly.FullName);
44+
}
45+
3446
[DataTestMethod]
3547
[DataRow(typeof(IOpenApiHttpTriggerContext))]
3648
[DataRow(typeof(OpenApiHttpTriggerContext))]
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"runtimeTarget": {
3+
"name": ".NETCoreApp,Version=v5.0",
4+
"signature": ""
5+
},
6+
"compilationOptions": {},
7+
"targets": {
8+
".NETCoreApp,Version=v5.0": {
9+
"Microsoft.Azure.Functions.Worker.Extensions.OpenApi/1.0.0": {
10+
"dependencies": {
11+
"Microsoft.Azure.Core.NewtonsoftJson": "1.0.0",
12+
"Microsoft.Azure.Functions.Worker.Core": "1.1.0",
13+
"Microsoft.Azure.Functions.Worker.Extensions.Http": "3.0.12",
14+
"Microsoft.Azure.WebJobs.Extensions.OpenApi.Core": "1.0.0"
15+
},
16+
"runtime": {
17+
"Microsoft.Azure.Functions.Worker.Extensions.OpenApi.dll": {}
18+
}
19+
}
20+
}
21+
}
22+
}

test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests/Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
<None Update="local.settings.json">
3838
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
3939
</None>
40+
<None Include="TestData\FakeDependencyFile.deps.json" Link="\%(Filename)%(Extension)">
41+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
42+
</None>
4043
</ItemGroup>
4144

4245
</Project>

test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Tests/OpenApiHttpTriggerContextTests.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,18 @@ public async Task Given_Type_When_Initiated_Then_It_Should_Return_ApplicationAss
3030
assembly.DefinedTypes.Select(p => p.FullName).Should().Contain(ti.FullName);
3131
}
3232

33+
[TestMethod]
34+
public async Task Given_Type_With_Referenced_Project_When_Initiated_Then_It_Should_Return_ApplicationAssemblyOfRootAssembly()
35+
{
36+
var location = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
37+
var context = new OpenApiHttpTriggerContext();
38+
39+
var assembly = (await context.SetApplicationAssemblyAsync(location, false))
40+
.ApplicationAssembly;
41+
42+
assembly.FullName.Should().Be(typeof(OpenApiHttpTriggerContextTests).Assembly.FullName);
43+
}
44+
3345
[DataTestMethod]
3446
[DataRow(typeof(IOpenApiHttpTriggerContext))]
3547
[DataRow(typeof(OpenApiHttpTriggerContext))]
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"runtimeTarget": {
3+
"name": ".NETStandard,Version=v2.0/",
4+
"signature": ""
5+
},
6+
"compilationOptions": {},
7+
"targets": {
8+
".NETStandard,Version=v2.0": {},
9+
".NETStandard,Version=v2.0/": {
10+
"Microsoft.Azure.WebJobs.Extensions.OpenApi/1.0.0": {
11+
"dependencies": {
12+
"Microsoft.Azure.WebJobs.Extensions.OpenApi.Core": "1.0.0",
13+
"Microsoft.Azure.WebJobs.Script.Abstractions": "1.0.0-preview",
14+
"NETStandard.Library": "2.0.3"
15+
},
16+
"runtime": {
17+
"Microsoft.Azure.WebJobs.Extensions.OpenApi.dll": {}
18+
}
19+
}
20+
}
21+
}
22+
}

0 commit comments

Comments
 (0)