Skip to content
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

Bugfix/function descriptions #5372

Merged
merged 3 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Fixed a bug where collection/array of primitive types members for union/intersection types would be ignored. [#5283](https://github.com/microsoft/kiota/issues/5283)
- Fixed a when generating a plugin when only an operation is selected in the root node in the extension. [#5300](https://github.com/microsoft/kiota/issues/5300)
- Fixed a bug where function descriptions in plugin manifest defaults to path summary instead of description[#5301](https://github.com/microsoft/kiota/issues/5301)

## [1.18.0] - 2024-09-05

Expand Down
54 changes: 27 additions & 27 deletions src/Kiota.Builder/Plugins/PluginsGenerationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
pluginDocument.Write(writer);
break;
case PluginType.APIManifest:
var apiManifest = new ApiManifestDocument("application"); //TODO add application name

Check warning on line 83 in src/Kiota.Builder/Plugins/PluginsGenerationService.cs

View workflow job for this annotation

GitHub Actions / Build

Complete the task associated to this 'TODO' comment. (https://rules.sonarsource.com/csharp/RSPEC-1135)

Check warning on line 83 in src/Kiota.Builder/Plugins/PluginsGenerationService.cs

View workflow job for this annotation

GitHub Actions / Build

Complete the task associated to this 'TODO' comment. (https://rules.sonarsource.com/csharp/RSPEC-1135)
// pass empty config hash so that its not included in this manifest.
apiManifest.ApiDependencies.AddOrReplace(Configuration.ClientClassName, Configuration.ToApiDependency(string.Empty, TreeNode?.GetRequestInfo().ToDictionary(static x => x.Key, static x => x.Value) ?? [], WorkingDirectory));
var publisherName = string.IsNullOrEmpty(OAIDocument.Info?.Contact?.Name)
Expand Down Expand Up @@ -138,7 +138,7 @@
}
return newSchema;
}
static OpenApiSchema? MergeAllOfInSchema(OpenApiSchema? schema)

Check warning on line 141 in src/Kiota.Builder/Plugins/PluginsGenerationService.cs

View workflow job for this annotation

GitHub Actions / Build

Refactor this static local function to reduce its Cognitive Complexity from 137 to the 15 allowed. (https://rules.sonarsource.com/csharp/RSPEC-3776)

Check warning on line 141 in src/Kiota.Builder/Plugins/PluginsGenerationService.cs

View workflow job for this annotation

GitHub Actions / Build

Refactor this static local function to reduce its Cognitive Complexity from 137 to the 15 allowed. (https://rules.sonarsource.com/csharp/RSPEC-3776)
{
if (schema?.AllOf is not { Count: > 0 }) return schema;
var newSchema = new OpenApiSchema();
Expand Down Expand Up @@ -259,8 +259,7 @@

private PluginManifestDocument GetManifestDocument(string openApiDocumentPath)
{
var (runtimes, functions) = GetRuntimesAndFunctionsFromTree(OAIDocument, Configuration.PluginAuthInformation, TreeNode, openApiDocumentPath);
var capabilities = GetPluginCapabilitiesFromFunctions(functions);
var (runtimes, functions, conversationStarters) = GetRuntimesFunctionsAndConversationStartersFromTree(OAIDocument, Configuration.PluginAuthInformation, TreeNode, openApiDocumentPath);
var descriptionForHuman = OAIDocument.Info?.Description.CleanupXMLString() is string d && !string.IsNullOrEmpty(d) ? d : $"Description for {OAIDocument.Info?.Title.CleanupXMLString()}";
var manifestInfo = ExtractInfoFromDocument(OAIDocument.Info);
var pluginManifestDocument = new PluginManifestDocument
Expand All @@ -287,11 +286,16 @@
Functions = [.. functions.OrderBy(static x => x.Name, StringComparer.OrdinalIgnoreCase)],
};

// Only add capabilities if there are any
if (capabilities != null)
{
pluginManifestDocument.Capabilities = capabilities;
}
if (conversationStarters.Length > 0)
pluginManifestDocument.Capabilities = new Capabilities
{
ConversationStarters = conversationStarters.Where(static x => !string.IsNullOrEmpty(x.Text))
.Select(static x => new ConversationStarter
{
Text = x.Text?.Length < 50 ? x.Text : x.Text?[..50]
})
.ToList()
};
return pluginManifestDocument;
}

Expand Down Expand Up @@ -334,11 +338,12 @@
string? PrivacyUrl = null,
string ContactEmail = DefaultContactEmail);

private static (OpenApiRuntime[], Function[]) GetRuntimesAndFunctionsFromTree(OpenApiDocument document, PluginAuthConfiguration? authInformation, OpenApiUrlTreeNode currentNode,
private static (OpenApiRuntime[], Function[], ConversationStarter[]) GetRuntimesFunctionsAndConversationStartersFromTree(OpenApiDocument document, PluginAuthConfiguration? authInformation, OpenApiUrlTreeNode currentNode,
string openApiDocumentPath)
{
var runtimes = new List<OpenApiRuntime>();
var functions = new List<Function>();
var conversationStarters = new List<ConversationStarter>();
var configAuth = authInformation?.ToPluginManifestAuth();
if (currentNode.PathItems.TryGetValue(Constants.DefaultOpenApiLabel, out var pathItem))
{
Expand All @@ -351,26 +356,34 @@
Spec = new OpenApiRuntimeSpec { Url = openApiDocumentPath, },
RunForFunctions = [operation.OperationId]
});

var summary = operation.Summary.CleanupXMLString();
var description = operation.Description.CleanupXMLString();

functions.Add(new Function
{
Name = operation.OperationId,
Description =
operation.Summary.CleanupXMLString() is { } summary && !string.IsNullOrEmpty(summary)
? summary
: operation.Description.CleanupXMLString(),
Description = !string.IsNullOrEmpty(description) ? description : summary,
States = GetStatesFromOperation(operation),

});
conversationStarters.Add(new ConversationStarter
{
Text = !string.IsNullOrEmpty(summary) ? summary : description
});

}
}

foreach (var node in currentNode.Children)
{
var (childRuntimes, childFunctions) = GetRuntimesAndFunctionsFromTree(document, authInformation, node.Value, openApiDocumentPath);
var (childRuntimes, childFunctions, childConversationStarters) = GetRuntimesFunctionsAndConversationStartersFromTree(document, authInformation, node.Value, openApiDocumentPath);
runtimes.AddRange(childRuntimes);
functions.AddRange(childFunctions);
conversationStarters.AddRange(childConversationStarters);
}

return (runtimes.ToArray(), functions.ToArray());
return (runtimes.ToArray(), functions.ToArray(), conversationStarters.ToArray());
}

private static Auth GetAuth(IList<OpenApiSecurityRequirement> securityRequirements)
Expand Down Expand Up @@ -437,17 +450,4 @@

return null;
}

private static Capabilities? GetPluginCapabilitiesFromFunctions(IList<Function> functions)
{
var conversionStarters = functions.Select(static x => x.Description)
.Where(static x => !string.IsNullOrEmpty(x))
.Select(static x => new ConversationStarter
{
Text = x.Length < 50 ? x : x[..50],
})
.ToList();

return conversionStarters.Count > 0 ? new Capabilities { ConversationStarters = conversionStarters } : null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,14 @@ public async Task GeneratesManifestAsync(string inputPluginName, string expected
paths:
/test:
get:
summary: summary for test path
description: description for test path
responses:
'200':
description: test
/test/{id}:
get:
summary: Summary for test path with id that is longer than 50 characters
description: description for test path with id
operationId: test.WithId
parameters:
Expand Down Expand Up @@ -107,8 +109,10 @@ public async Task GeneratesManifestAsync(string inputPluginName, string expected
Assert.NotNull(resultingManifest.Document);
Assert.Equal($"{expectedPluginName.ToLower()}-openapi.yml", resultingManifest.Document.Runtimes.OfType<OpenApiRuntime>().First().Spec.Url);
Assert.Equal(2, resultingManifest.Document.Functions.Count);// all functions are generated despite missing operationIds
Assert.Contains("description for test path with id", resultingManifest.Document.Functions[1].Description);// Uses the operation description
Assert.Equal(2, resultingManifest.Document.Capabilities.ConversationStarters.Count);// conversation starters are generated for each function
Assert.True(resultingManifest.Document.Capabilities.ConversationStarters[0].Text.Length < 50);// Conversation starters are limited to 50 characters
Assert.Contains("Summary for test path with id", resultingManifest.Document.Capabilities.ConversationStarters[1].Text);// Uses the operation summary
Assert.True(resultingManifest.Document.Capabilities.ConversationStarters[1].Text.Length <= 50);// Conversation starters are limited to 50 characters
Assert.Equal(expectedPluginName, resultingManifest.Document.Namespace);// namespace is cleaned up.
Assert.Empty(resultingManifest.Problems);// no problems are expected with names
}
Expand Down
Loading