From 68a35575334f09bede511a34ced3998fe834d6c3 Mon Sep 17 00:00:00 2001 From: Andrew Omondi Date: Tue, 16 Apr 2024 13:51:09 +0300 Subject: [PATCH 1/7] Fixes breaking changes from latest update from manifest lib --- .vscode/launch.json | 2 +- src/Kiota.Builder/Kiota.Builder.csproj | 2 +- src/Kiota.Builder/KiotaBuilder.cs | 4 +- src/Kiota.Builder/PluginType.cs | 3 +- src/Kiota.Builder/Plugins/AuthComparer.cs | 2 +- .../Plugins/OpenAPiRuntimeComparer.cs | 9 +- .../Plugins/OpenApiRuntimeSpecComparer.cs | 23 +++++ .../Plugins/PluginsGenerationService.cs | 91 +++++++++++-------- src/kiota/Handlers/Plugin/AddHandler.cs | 1 - .../Plugins/OpenAPIRuntimeComparerTests.cs | 4 +- 10 files changed, 90 insertions(+), 51 deletions(-) create mode 100644 src/Kiota.Builder/Plugins/OpenApiRuntimeSpecComparer.cs diff --git a/.vscode/launch.json b/.vscode/launch.json index 34885c1e13..9035ac11ff 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -330,7 +330,7 @@ "-i", "**/messages", "--type", - "APIManifest" + "microsoft" ], "cwd": "${workspaceFolder}/samples/msgraph-mail/dotnet", "console": "internalConsole", diff --git a/src/Kiota.Builder/Kiota.Builder.csproj b/src/Kiota.Builder/Kiota.Builder.csproj index faa7c7dd75..bee0e291c5 100644 --- a/src/Kiota.Builder/Kiota.Builder.csproj +++ b/src/Kiota.Builder/Kiota.Builder.csproj @@ -47,7 +47,7 @@ - + GeneratePluginAsync(CancellationToken cancellationToken) { return await GenerateConsumerAsync(async (sw, stepId, openApiTree, CancellationToken) => { - if (config.PluginTypes.Contains(PluginType.OpenAI)) - throw new NotImplementedException("The OpenAI plugin type is not supported for generation"); + if (config.PluginTypes.Any(static pluginType => pluginType != PluginType.Microsoft)) + throw new NotImplementedException("Only the Microsoft plugin type is not supported for generation"); if (openApiDocument is null || openApiTree is null) throw new InvalidOperationException("The OpenAPI document and the URL tree must be loaded before generating the plugins"); // generate plugin diff --git a/src/Kiota.Builder/PluginType.cs b/src/Kiota.Builder/PluginType.cs index b0285d4747..b985a129b0 100644 --- a/src/Kiota.Builder/PluginType.cs +++ b/src/Kiota.Builder/PluginType.cs @@ -3,5 +3,6 @@ public enum PluginType { OpenAI, - APIManifest + APIManifest, + Microsoft } diff --git a/src/Kiota.Builder/Plugins/AuthComparer.cs b/src/Kiota.Builder/Plugins/AuthComparer.cs index a38c781692..e5212d44de 100644 --- a/src/Kiota.Builder/Plugins/AuthComparer.cs +++ b/src/Kiota.Builder/Plugins/AuthComparer.cs @@ -16,6 +16,6 @@ public bool Equals(Auth? x, Auth? y) public int GetHashCode([DisallowNull] Auth obj) { if (obj == null) return 0; - return string.IsNullOrEmpty(obj.Type) ? 0 : StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Type) * 3; + return obj.Type is null ? 0 : StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Type.Value.ToString()) * 3; } } diff --git a/src/Kiota.Builder/Plugins/OpenAPiRuntimeComparer.cs b/src/Kiota.Builder/Plugins/OpenAPiRuntimeComparer.cs index 944cc78d39..fc699b070e 100644 --- a/src/Kiota.Builder/Plugins/OpenAPiRuntimeComparer.cs +++ b/src/Kiota.Builder/Plugins/OpenAPiRuntimeComparer.cs @@ -7,7 +7,7 @@ namespace Kiota.Builder.Plugins; -internal class OpenAPIRuntimeComparer : IEqualityComparer +internal class OpenAPIRuntimeComparer : IEqualityComparer { public bool EvaluateFunctions { @@ -15,17 +15,18 @@ public bool EvaluateFunctions } private static readonly StringIEnumerableDeepComparer _stringIEnumerableDeepComparer = new(); private static readonly AuthComparer _authComparer = new(); + private static readonly OpenApiRuntimeSpecComparer _openApiRuntimeSpecComparer = new(); /// - public bool Equals(OpenAPIRuntime? x, OpenAPIRuntime? y) + public bool Equals(OpenApiRuntime? x, OpenApiRuntime? y) { return x == null && y == null || x != null && y != null && GetHashCode(x) == GetHashCode(y); } /// - public int GetHashCode([DisallowNull] OpenAPIRuntime obj) + public int GetHashCode([DisallowNull] OpenApiRuntime obj) { if (obj == null) return 0; return (EvaluateFunctions ? _stringIEnumerableDeepComparer.GetHashCode(obj.RunForFunctions ?? Enumerable.Empty()) * 7 : 0) + - obj.Spec.Select(static x => StringComparer.Ordinal.GetHashCode($"{x.Key}:{x.Value}")).Aggregate(0, (acc, next) => acc + next) * 5 + + (obj.Spec is null ? 0 : _openApiRuntimeSpecComparer.GetHashCode(obj.Spec) * 5) + (obj.Auth is null ? 0 : _authComparer.GetHashCode(obj.Auth) * 3); } } diff --git a/src/Kiota.Builder/Plugins/OpenApiRuntimeSpecComparer.cs b/src/Kiota.Builder/Plugins/OpenApiRuntimeSpecComparer.cs new file mode 100644 index 0000000000..38de08d0cf --- /dev/null +++ b/src/Kiota.Builder/Plugins/OpenApiRuntimeSpecComparer.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Microsoft.Plugins.Manifest; + +namespace Kiota.Builder.Plugins; + +public class OpenApiRuntimeSpecComparer : IEqualityComparer +{ + /// + public bool Equals(OpenApiRuntimeSpec? x, OpenApiRuntimeSpec? y) + { + return x == null && y == null || x != null && y != null && GetHashCode(x) == GetHashCode(y); + } + /// + public int GetHashCode([DisallowNull] OpenApiRuntimeSpec obj) + { + if (obj == null) return 0; + return (string.IsNullOrEmpty(obj.Url) ? 0 : StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Url) * 5) + + (string.IsNullOrEmpty(obj.ApiDescription) ? 0 : StringComparer.OrdinalIgnoreCase.GetHashCode(obj.ApiDescription) * 3); + } +} diff --git a/src/Kiota.Builder/Plugins/PluginsGenerationService.cs b/src/Kiota.Builder/Plugins/PluginsGenerationService.cs index bc0c3e4bf7..354e5bbe4a 100644 --- a/src/Kiota.Builder/Plugins/PluginsGenerationService.cs +++ b/src/Kiota.Builder/Plugins/PluginsGenerationService.cs @@ -30,31 +30,37 @@ public PluginsGenerationService(OpenApiDocument document, OpenApiUrlTreeNode ope Configuration = configuration; } private static readonly OpenAPIRuntimeComparer _openAPIRuntimeComparer = new(); - private const string ManifestFileName = "manifest.json"; + private const string ManifestFileNameSuffix = ".json"; private const string DescriptionRelativePath = "./openapi.yml"; public async Task GenerateManifestAsync(CancellationToken cancellationToken = default) { - var manifestOutputPath = Path.Combine(Configuration.OutputPath, ManifestFileName); - var directory = Path.GetDirectoryName(manifestOutputPath); - if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) - Directory.CreateDirectory(directory); + foreach (var pluginType in Configuration.PluginTypes) + { + if (pluginType != PluginType.Microsoft) + continue; //TODO add support for other plugin type generation + + var manifestOutputPath = Path.Combine(Configuration.OutputPath, $"{Configuration.ClientClassName.ToLowerInvariant()}-{pluginType.ToString().ToLowerInvariant()}{ManifestFileNameSuffix}"); + var directory = Path.GetDirectoryName(manifestOutputPath); + if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) + Directory.CreateDirectory(directory); - var descriptionFullPath = Path.Combine(Configuration.OutputPath, DescriptionRelativePath); + var descriptionFullPath = Path.Combine(Configuration.OutputPath, DescriptionRelativePath); #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task - await using var descriptionStream = File.Create(descriptionFullPath, 4096); - await using var fileWriter = new StreamWriter(descriptionStream); - var descriptionWriter = new OpenApiYamlWriter(fileWriter); - OAIDocument.SerializeAsV3(descriptionWriter); - descriptionWriter.Flush(); + await using var descriptionStream = File.Create(descriptionFullPath, 4096); + await using var fileWriter = new StreamWriter(descriptionStream); + var descriptionWriter = new OpenApiYamlWriter(fileWriter); + OAIDocument.SerializeAsV3(descriptionWriter); + descriptionWriter.Flush(); - var pluginDocument = GetManifestDocument(DescriptionRelativePath); - await using var fileStream = File.Create(manifestOutputPath, 4096); - await using var writer = new Utf8JsonWriter(fileStream, new JsonWriterOptions { Indented = true }); + var pluginDocument = GetManifestDocument(DescriptionRelativePath); + await using var fileStream = File.Create(manifestOutputPath, 4096); + await using var writer = new Utf8JsonWriter(fileStream, new JsonWriterOptions { Indented = true }); #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task - pluginDocument.Write(writer); - await writer.FlushAsync(cancellationToken).ConfigureAwait(false); + pluginDocument.Write(writer); + await writer.FlushAsync(cancellationToken).ConfigureAwait(false); + } } - private ManifestDocument GetManifestDocument(string openApiDocumentPath) + private PluginManifestDocument GetManifestDocument(string openApiDocumentPath) { var (runtimes, functions) = GetRuntimesAndFunctionsFromTree(TreeNode, openApiDocumentPath); var descriptionForHuman = OAIDocument.Info?.Description.CleanupXMLString() is string d && !string.IsNullOrEmpty(d) ? d : $"Description for {OAIDocument.Info?.Title.CleanupXMLString()}"; @@ -64,7 +70,6 @@ private ManifestDocument GetManifestDocument(string openApiDocumentPath) string? privacyUrl = null; if (OAIDocument.Info is not null) { - if (OAIDocument.Info.Extensions.TryGetValue(OpenApiDescriptionForModelExtension.Name, out var descriptionExtension) && descriptionExtension is OpenApiDescriptionForModelExtension extension && !string.IsNullOrEmpty(extension.Description)) @@ -76,7 +81,7 @@ descriptionExtension is OpenApiDescriptionForModelExtension extension && if (OAIDocument.Info.Extensions.TryGetValue(OpenApiPrivacyPolicyUrlExtension.Name, out var privacyExtension) && privacyExtension is OpenApiPrivacyPolicyUrlExtension privacy) privacyUrl = privacy.Privacy; } - return new ManifestDocument + return new PluginManifestDocument { SchemaVersion = "v2", NameForHuman = OAIDocument.Info?.Title.CleanupXMLString(), @@ -100,18 +105,21 @@ descriptionExtension is OpenApiDescriptionForModelExtension extension && Functions = [.. functions.OrderBy(static x => x.Name, StringComparer.OrdinalIgnoreCase)] }; } - private (OpenAPIRuntime[], Function[]) GetRuntimesAndFunctionsFromTree(OpenApiUrlTreeNode currentNode, string openApiDocumentPath) + private (OpenApiRuntime[], Function[]) GetRuntimesAndFunctionsFromTree(OpenApiUrlTreeNode currentNode, string openApiDocumentPath) { - var runtimes = new List(); + var runtimes = new List(); var functions = new List(); if (currentNode.PathItems.TryGetValue(Constants.DefaultOpenApiLabel, out var pathItem)) { foreach (var operation in pathItem.Operations.Values.Where(static x => !string.IsNullOrEmpty(x.OperationId))) { - runtimes.Add(new OpenAPIRuntime + runtimes.Add(new OpenApiRuntime { - Auth = new Auth("none"), - Spec = new Dictionary { { "url", openApiDocumentPath } }, + Auth = new AnonymousAuth(), + Spec = new OpenApiRuntimeSpec() + { + Url = openApiDocumentPath + }, RunForFunctions = [operation.OperationId] }); var oasParameters = operation.Parameters @@ -123,19 +131,26 @@ descriptionExtension is OpenApiDescriptionForModelExtension extension && functions.Add(new Function { Name = operation.OperationId, - Description = operation.Summary.CleanupXMLString() is string summary && !string.IsNullOrEmpty(summary) ? summary : operation.Description.CleanupXMLString(), - Parameters = oasParameters.Length == 0 ? null : - new Parameters( - "object", - new Properties(oasParameters.ToDictionary( - static x => x.Name, - static x => new Property( - x.Schema.Type ?? string.Empty, - x.Description.CleanupXMLString(), - x.Schema.Default?.ToString() ?? string.Empty, - null), //TODO enums - StringComparer.OrdinalIgnoreCase)), - oasParameters.Where(static x => x.Required).Select(static x => x.Name).ToList()), + Description = + operation.Summary.CleanupXMLString() is string summary && !string.IsNullOrEmpty(summary) + ? summary + : operation.Description.CleanupXMLString(), + Parameters = oasParameters.Length == 0 + ? null + : new Parameters + { + Type = "object", + Properties = new Properties(oasParameters.ToDictionary( + static x => x.Name, + static x => new FunctionParameter() + { + Type = x.Schema.Type ?? string.Empty, + Description = x.Description.CleanupXMLString(), + Default = x.Schema.Default?.ToString() ?? string.Empty, + //TODO enums + })), + Required = oasParameters.Where(static x => x.Required).Select(static x => x.Name).ToList() + }, States = GetStatesFromOperation(operation), }); } @@ -177,7 +192,7 @@ rExtRaw is T rExt && { return new State { - Instructions = instructionsExtractor(rExt).Where(static x => !string.IsNullOrEmpty(x)).Select(static x => x.CleanupXMLString()).ToList() + Instructions = new Instructions(instructionsExtractor(rExt).Where(static x => !string.IsNullOrEmpty(x)).Select(static x => x.CleanupXMLString()).ToList()) }; } return null; diff --git a/src/kiota/Handlers/Plugin/AddHandler.cs b/src/kiota/Handlers/Plugin/AddHandler.cs index 2f150fcd82..be662926cd 100644 --- a/src/kiota/Handlers/Plugin/AddHandler.cs +++ b/src/kiota/Handlers/Plugin/AddHandler.cs @@ -94,6 +94,5 @@ public override async Task InvokeAsync(InvocationContext context) #endif } } - throw new NotImplementedException(); } } diff --git a/tests/Kiota.Builder.Tests/Plugins/OpenAPIRuntimeComparerTests.cs b/tests/Kiota.Builder.Tests/Plugins/OpenAPIRuntimeComparerTests.cs index 936f073ac3..97808aa1c9 100644 --- a/tests/Kiota.Builder.Tests/Plugins/OpenAPIRuntimeComparerTests.cs +++ b/tests/Kiota.Builder.Tests/Plugins/OpenAPIRuntimeComparerTests.cs @@ -17,8 +17,8 @@ public void Defensive() [Fact] public void GetsHashCode() { - var runtime1 = new OpenAPIRuntime { Spec = new() { { "key1", "value1" } } }; - var runtime2 = new OpenAPIRuntime { Spec = new() { { "key2", "value2" } }, Auth = new() { Type = "type" } }; + var runtime1 = new OpenApiRuntime { Spec = new() { Url = "url", ApiDescription = "description" } }; + var runtime2 = new OpenApiRuntime { Spec = new() { Url = "url", ApiDescription = "description" }, Auth = new AnonymousAuth() }; Assert.NotEqual(_comparer.GetHashCode(runtime1), _comparer.GetHashCode(runtime2)); } } From 9f9d0bbd5d20a97e7165f052e3b1e2b331738b2f Mon Sep 17 00:00:00 2001 From: Andrew Omondi Date: Tue, 16 Apr 2024 14:51:43 +0300 Subject: [PATCH 2/7] Fix test --- .../Plugins/PluginsGenerationServiceTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs b/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs index 83baa0ba06..5651aee580 100644 --- a/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs +++ b/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs @@ -49,7 +49,7 @@ public async Task GeneratesManifest() { OutputPath = outputDirectory, OpenAPIFilePath = "openapiPath", - PluginTypes = [PluginType.APIManifest], + PluginTypes = [PluginType.Microsoft], ClientClassName = "client", }; var (openAPIDocumentStream, _) = await openAPIDocumentDS.LoadStreamAsync(simpleDescriptionPath, generationConfiguration, null, false); @@ -59,7 +59,7 @@ public async Task GeneratesManifest() var pluginsGenerationService = new PluginsGenerationService(openApiDocument, urlTreeNode, generationConfiguration); await pluginsGenerationService.GenerateManifestAsync(); - Assert.True(File.Exists(Path.Combine(outputDirectory, "manifest.json"))); + Assert.True(File.Exists(Path.Combine(outputDirectory, "client-microsoft.json"))); Assert.True(File.Exists(Path.Combine(outputDirectory, "openapi.yml"))); } } From 0fe8875699fb78e3252b206fe41509ced9c3c4a9 Mon Sep 17 00:00:00 2001 From: Andrew Omondi Date: Wed, 17 Apr 2024 11:36:32 +0300 Subject: [PATCH 3/7] Bump manifest and plugins versions --- src/Kiota.Builder/Kiota.Builder.csproj | 2 +- src/kiota/kiota.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Kiota.Builder.csproj b/src/Kiota.Builder/Kiota.Builder.csproj index bee0e291c5..e8aebabd07 100644 --- a/src/Kiota.Builder/Kiota.Builder.csproj +++ b/src/Kiota.Builder/Kiota.Builder.csproj @@ -47,7 +47,7 @@ - + - + From 691a5885024e4841418d681a3eb37a256a4d9ecf Mon Sep 17 00:00:00 2001 From: Andrew Omondi Date: Thu, 18 Apr 2024 10:10:16 +0300 Subject: [PATCH 4/7] Add support for api manifest generation --- .vscode/launch.json | 42 ++++++++++++++---- src/Kiota.Builder/KiotaBuilder.cs | 4 +- .../Plugins/PluginsGenerationService.cs | 43 +++++++++++++------ 3 files changed, 66 insertions(+), 23 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 9035ac11ff..cdb61f49af 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -196,7 +196,10 @@ "request": "launch", "preLaunchTask": "build", "program": "${workspaceFolder}/src/kiota/bin/Debug/net8.0/kiota.dll", - "args": ["search", "microsoft"], + "args": [ + "search", + "microsoft" + ], "cwd": "${workspaceFolder}/src/kiota", "console": "internalConsole", "stopAtEntry": false @@ -207,7 +210,10 @@ "request": "launch", "preLaunchTask": "build", "program": "${workspaceFolder}/src/kiota/bin/Debug/net8.0/kiota.dll", - "args": ["search", "test"], + "args": [ + "search", + "test" + ], "cwd": "${workspaceFolder}/src/kiota", "console": "internalConsole", "stopAtEntry": false @@ -249,7 +255,11 @@ "request": "launch", "preLaunchTask": "build", "program": "${workspaceFolder}/src/kiota/bin/Debug/net8.0/kiota.dll", - "args": ["info", "-l", "CSharp"], + "args": [ + "info", + "-l", + "CSharp" + ], "cwd": "${workspaceFolder}/src/kiota", "console": "internalConsole", "stopAtEntry": false @@ -260,7 +270,11 @@ "request": "launch", "preLaunchTask": "build", "program": "${workspaceFolder}/src/kiota/bin/Debug/net8.0/kiota.dll", - "args": ["update", "-o", "${workspaceFolder}/samples"], + "args": [ + "update", + "-o", + "${workspaceFolder}/samples" + ], "cwd": "${workspaceFolder}/src/kiota", "console": "internalConsole", "stopAtEntry": false @@ -271,7 +285,10 @@ "request": "launch", "preLaunchTask": "build", "program": "${workspaceFolder}/src/kiota/bin/Debug/net8.0/kiota.dll", - "args": ["workspace", "migrate"], + "args": [ + "workspace", + "migrate" + ], "cwd": "${workspaceFolder}/samples/msgraph-mail/dotnet", "console": "internalConsole", "stopAtEntry": false, @@ -285,7 +302,10 @@ "request": "launch", "preLaunchTask": "build", "program": "${workspaceFolder}/src/kiota/bin/Debug/net8.0/kiota.dll", - "args": ["client", "generate"], + "args": [ + "client", + "generate" + ], "cwd": "${workspaceFolder}/samples/msgraph-mail/dotnet", "console": "internalConsole", "stopAtEntry": false, @@ -330,6 +350,8 @@ "-i", "**/messages", "--type", + "ApiManifest", + "--type", "microsoft" ], "cwd": "${workspaceFolder}/samples/msgraph-mail/dotnet", @@ -345,7 +367,11 @@ "request": "launch", "preLaunchTask": "build", "program": "${workspaceFolder}/src/kiota/bin/Debug/net8.0/kiota.dll", - "args": ["login", "github", "device"], + "args": [ + "login", + "github", + "device" + ], "cwd": "${workspaceFolder}/src/kiota", "console": "internalConsole", "stopAtEntry": false @@ -357,4 +383,4 @@ "processId": "${command:pickProcess}" } ] -} +} \ No newline at end of file diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs index 9111119604..5b7c2b6f0f 100644 --- a/src/Kiota.Builder/KiotaBuilder.cs +++ b/src/Kiota.Builder/KiotaBuilder.cs @@ -231,8 +231,8 @@ public async Task GeneratePluginAsync(CancellationToken cancellationToken) { return await GenerateConsumerAsync(async (sw, stepId, openApiTree, CancellationToken) => { - if (config.PluginTypes.Any(static pluginType => pluginType != PluginType.Microsoft)) - throw new NotImplementedException("Only the Microsoft plugin type is not supported for generation"); + if (config.PluginTypes.Contains(PluginType.OpenAI)) + throw new NotImplementedException("The OpenAI plugin type is not supported for generation"); if (openApiDocument is null || openApiTree is null) throw new InvalidOperationException("The OpenAPI document and the URL tree must be loaded before generating the plugins"); // generate plugin diff --git a/src/Kiota.Builder/Plugins/PluginsGenerationService.cs b/src/Kiota.Builder/Plugins/PluginsGenerationService.cs index 354e5bbe4a..63f1ad1c6e 100644 --- a/src/Kiota.Builder/Plugins/PluginsGenerationService.cs +++ b/src/Kiota.Builder/Plugins/PluginsGenerationService.cs @@ -8,6 +8,8 @@ using Kiota.Builder.Configuration; using Kiota.Builder.Extensions; using Kiota.Builder.OpenApiExtensions; +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.OpenApi.ApiManifest; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; using Microsoft.OpenApi.Writers; @@ -34,29 +36,44 @@ public PluginsGenerationService(OpenApiDocument document, OpenApiUrlTreeNode ope private const string DescriptionRelativePath = "./openapi.yml"; public async Task GenerateManifestAsync(CancellationToken cancellationToken = default) { + // write the decription + var descriptionFullPath = Path.Combine(Configuration.OutputPath, DescriptionRelativePath); +#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task + await using var descriptionStream = File.Create(descriptionFullPath, 4096); + await using var fileWriter = new StreamWriter(descriptionStream); +#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task + var descriptionWriter = new OpenApiYamlWriter(fileWriter); + OAIDocument.SerializeAsV3(descriptionWriter); + descriptionWriter.Flush(); + + // write the plugins foreach (var pluginType in Configuration.PluginTypes) { - if (pluginType != PluginType.Microsoft) - continue; //TODO add support for other plugin type generation - var manifestOutputPath = Path.Combine(Configuration.OutputPath, $"{Configuration.ClientClassName.ToLowerInvariant()}-{pluginType.ToString().ToLowerInvariant()}{ManifestFileNameSuffix}"); var directory = Path.GetDirectoryName(manifestOutputPath); if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) Directory.CreateDirectory(directory); - - var descriptionFullPath = Path.Combine(Configuration.OutputPath, DescriptionRelativePath); #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task - await using var descriptionStream = File.Create(descriptionFullPath, 4096); - await using var fileWriter = new StreamWriter(descriptionStream); - var descriptionWriter = new OpenApiYamlWriter(fileWriter); - OAIDocument.SerializeAsV3(descriptionWriter); - descriptionWriter.Flush(); - - var pluginDocument = GetManifestDocument(DescriptionRelativePath); await using var fileStream = File.Create(manifestOutputPath, 4096); await using var writer = new Utf8JsonWriter(fileStream, new JsonWriterOptions { Indented = true }); #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task - pluginDocument.Write(writer); + + switch (pluginType) + { + case PluginType.Microsoft: + var pluginDocument = GetManifestDocument(DescriptionRelativePath); + pluginDocument.Write(writer); + break; + case PluginType.APIManifest: + var apiManifest = new ApiManifestDocument("application"); //TODO add application name + apiManifest.ApiDependencies.AddOrReplace(Configuration.ClientClassName, Configuration.ToApiDependency(OAIDocument.HashCode ?? string.Empty, TreeNode?.GetRequestInfo().ToDictionary(static x => x.Key, static x => x.Value) ?? [])); + apiManifest.Write(writer); + break; + case PluginType.OpenAI: + //TODO add support for OpenAI plugin type generation + default: + continue; + } await writer.FlushAsync(cancellationToken).ConfigureAwait(false); } } From a065bded3694287d4bdab6c5ed4468f2dc7d1d5d Mon Sep 17 00:00:00 2001 From: Andrew Omondi Date: Thu, 18 Apr 2024 10:35:37 +0300 Subject: [PATCH 5/7] Adds support for manifest generation --- src/Kiota.Builder/Plugins/PluginsGenerationService.cs | 6 +++--- .../Plugins/PluginsGenerationServiceTests.cs | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Kiota.Builder/Plugins/PluginsGenerationService.cs b/src/Kiota.Builder/Plugins/PluginsGenerationService.cs index 63f1ad1c6e..667020730d 100644 --- a/src/Kiota.Builder/Plugins/PluginsGenerationService.cs +++ b/src/Kiota.Builder/Plugins/PluginsGenerationService.cs @@ -38,6 +38,9 @@ public async Task GenerateManifestAsync(CancellationToken cancellationToken = de { // write the decription var descriptionFullPath = Path.Combine(Configuration.OutputPath, DescriptionRelativePath); + var directory = Path.GetDirectoryName(descriptionFullPath); + if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) + Directory.CreateDirectory(directory); #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task await using var descriptionStream = File.Create(descriptionFullPath, 4096); await using var fileWriter = new StreamWriter(descriptionStream); @@ -50,9 +53,6 @@ public async Task GenerateManifestAsync(CancellationToken cancellationToken = de foreach (var pluginType in Configuration.PluginTypes) { var manifestOutputPath = Path.Combine(Configuration.OutputPath, $"{Configuration.ClientClassName.ToLowerInvariant()}-{pluginType.ToString().ToLowerInvariant()}{ManifestFileNameSuffix}"); - var directory = Path.GetDirectoryName(manifestOutputPath); - if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) - Directory.CreateDirectory(directory); #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task await using var fileStream = File.Create(manifestOutputPath, 4096); await using var writer = new Utf8JsonWriter(fileStream, new JsonWriterOptions { Indented = true }); diff --git a/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs b/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs index 5651aee580..77e2b4a638 100644 --- a/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs +++ b/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs @@ -33,6 +33,9 @@ public async Task GeneratesManifest() info: title: test version: 1.0 +servers: + - url: http://localhost/ + description: There's no place like home paths: /test: get: @@ -49,8 +52,9 @@ public async Task GeneratesManifest() { OutputPath = outputDirectory, OpenAPIFilePath = "openapiPath", - PluginTypes = [PluginType.Microsoft], + PluginTypes = [PluginType.Microsoft, PluginType.APIManifest], ClientClassName = "client", + ApiRootUrl = "http://localhost/", //Kiota builder would set this for us }; var (openAPIDocumentStream, _) = await openAPIDocumentDS.LoadStreamAsync(simpleDescriptionPath, generationConfiguration, null, false); var openApiDocument = await openAPIDocumentDS.GetDocumentFromStreamAsync(openAPIDocumentStream, generationConfiguration); @@ -60,6 +64,7 @@ public async Task GeneratesManifest() await pluginsGenerationService.GenerateManifestAsync(); Assert.True(File.Exists(Path.Combine(outputDirectory, "client-microsoft.json"))); + Assert.True(File.Exists(Path.Combine(outputDirectory, "client-apimanifest.json"))); Assert.True(File.Exists(Path.Combine(outputDirectory, "openapi.yml"))); } } From 6cbc4536861215e3a6432d4e62f1b2f844f7160e Mon Sep 17 00:00:00 2001 From: Andrew Omondi Date: Fri, 19 Apr 2024 15:45:54 +0300 Subject: [PATCH 6/7] Throw error for not supported case --- src/Kiota.Builder/Plugins/PluginsGenerationService.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Kiota.Builder/Plugins/PluginsGenerationService.cs b/src/Kiota.Builder/Plugins/PluginsGenerationService.cs index 667020730d..ed8c865230 100644 --- a/src/Kiota.Builder/Plugins/PluginsGenerationService.cs +++ b/src/Kiota.Builder/Plugins/PluginsGenerationService.cs @@ -69,10 +69,10 @@ public async Task GenerateManifestAsync(CancellationToken cancellationToken = de apiManifest.ApiDependencies.AddOrReplace(Configuration.ClientClassName, Configuration.ToApiDependency(OAIDocument.HashCode ?? string.Empty, TreeNode?.GetRequestInfo().ToDictionary(static x => x.Key, static x => x.Value) ?? [])); apiManifest.Write(writer); break; - case PluginType.OpenAI: - //TODO add support for OpenAI plugin type generation + case PluginType.OpenAI://TODO add support for OpenAI plugin type generation + // intentional drop to the default case default: - continue; + throw new NotImplementedException($"The {pluginType} plugin is not implemented."); } await writer.FlushAsync(cancellationToken).ConfigureAwait(false); } From 3c5852a4e4519a4b26d6040df1cc0658e792c04a Mon Sep 17 00:00:00 2001 From: Andrew Omondi Date: Fri, 19 Apr 2024 15:55:49 +0300 Subject: [PATCH 7/7] Fix formatting --- src/Kiota.Builder/Plugins/PluginsGenerationService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Plugins/PluginsGenerationService.cs b/src/Kiota.Builder/Plugins/PluginsGenerationService.cs index ed8c865230..09f073b182 100644 --- a/src/Kiota.Builder/Plugins/PluginsGenerationService.cs +++ b/src/Kiota.Builder/Plugins/PluginsGenerationService.cs @@ -70,7 +70,7 @@ public async Task GenerateManifestAsync(CancellationToken cancellationToken = de apiManifest.Write(writer); break; case PluginType.OpenAI://TODO add support for OpenAI plugin type generation - // intentional drop to the default case + // intentional drop to the default case default: throw new NotImplementedException($"The {pluginType} plugin is not implemented."); }