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

feat/bundle dependencies #5397

Merged
merged 14 commits into from
Sep 12, 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 stack overflow in the core generator caused by circular comparisons. [#5369](https://github.com/microsoft/kiota/issues/5369)
- 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)
- Updated dependencies command and view to reflect the availability of bundles. [#5317](https://github.com/microsoft/kiota/issues/5317)
- 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)
- Fixed a bug where TypeScript would not properly build URIs with uppercase first characters query parameter names.[#5382](https://github.com/microsoft/kiota/issues/5382)
Expand Down
51 changes: 43 additions & 8 deletions scripts/update-versions.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ function Retry-Command {
}
}

function Get-QueryName {
Param(
$dependency
)
$dependency.QueryName ?? $dependency.Name
}

# Read the appsettings.json file
$mainSettings = Join-Path -Path $PSScriptRoot -ChildPath "..\src\kiota\appsettings.json"
$appSettings = Get-Content -Path $mainSettings -Raw | ConvertFrom-Json
Expand All @@ -113,62 +120,90 @@ foreach ($languageName in ($appSettings.Languages | Get-Member -MemberType NoteP
$language = $appSettings.Languages.$languageName
if ($languageName -eq "CSharp" -or $languageName -eq "CLI") {
foreach ($dependency in $language.Dependencies) {
if ($null -ne $dependency.MaximumVersion -and $dependency.MaximumVersion -eq $dependency.Version) {
Write-Information "Skipping $($dependency.Name) as it's already at the maximum version"
continue
}
Retry-Command -ScriptBlock {
$latestVersion = Get-LatestNugetVersion -packageId $dependency.Name
$latestVersion = Get-LatestNugetVersion -packageId (Get-QueryName -dependency $dependency)
Write-Information "Updating $($dependency.Name) from $($dependency.Version) to $latestVersion"
$dependency.Version = $latestVersion
}
}
}
elseif ($languageName -eq "Go") {
foreach ($dependency in $language.Dependencies) {
if ($null -ne $dependency.MaximumVersion -and $dependency.MaximumVersion -eq $dependency.Version) {
Write-Information "Skipping $($dependency.Name) as it's already at the maximum version"
continue
}
Retry-Command -ScriptBlock {
$latestVersion = Get-LatestGithubRelease -packageId $dependency.Name
$latestVersion = Get-LatestGithubRelease -packageId (Get-QueryName -dependency $dependency)
Write-Information "Updating $($dependency.Name) from $($dependency.Version) to $latestVersion"
$dependency.Version = $latestVersion
}
}
}
elseif ($languageName -eq "TypeScript") {
foreach ($dependency in $language.Dependencies) {
if ($null -ne $dependency.MaximumVersion -and $dependency.MaximumVersion -eq $dependency.Version) {
Write-Information "Skipping $($dependency.Name) as it's already at the maximum version"
continue
}
Retry-Command -ScriptBlock {
$latestVersion = Get-LatestNpmVersion -packageId $dependency.Name
$latestVersion = Get-LatestNpmVersion -packageId (Get-QueryName -dependency $dependency)
Write-Information "Updating $($dependency.Name) from $($dependency.Version) to $latestVersion"
$dependency.Version = $latestVersion
}
}
}
elseif ($languageName -eq "Java") {
foreach ($dependency in $language.Dependencies) {
if ($null -ne $dependency.MaximumVersion -and $dependency.MaximumVersion -eq $dependency.Version) {
Write-Information "Skipping $($dependency.Name) as it's already at the maximum version"
continue
}
Retry-Command -ScriptBlock {
$latestVersion = Get-LatestMavenVersion -packageId $dependency.Name.Replace("jakarta.annotation:jakarta.annotation-api", "jakarta/annotation.jakarta|annotation-api")
$latestVersion = Get-LatestMavenVersion -packageId (Get-QueryName -dependency $dependency)
Write-Information "Updating $($dependency.Name) from $($dependency.Version) to $latestVersion"
$dependency.Version = $latestVersion
}
}
}
elseif ($languageName -eq "PHP") {
foreach ($dependency in $language.Dependencies) {
if ($null -ne $dependency.MaximumVersion -and $dependency.MaximumVersion -eq $dependency.Version) {
Write-Information "Skipping $($dependency.Name) as it's already at the maximum version"
continue
}
Retry-Command -ScriptBlock {
$latestVersion = Get-LatestComposerVersion -packageId $dependency.Name
$latestVersion = Get-LatestComposerVersion -packageId (Get-QueryName -dependency $dependency)
Write-Information "Updating $($dependency.Name) from $($dependency.Version) to $latestVersion"
$dependency.Version = $latestVersion
}
}
}
elseif ($languageName -eq "Python") {
foreach ($dependency in $language.Dependencies) {
if ($null -ne $dependency.MaximumVersion -and $dependency.MaximumVersion -eq $dependency.Version) {
Write-Information "Skipping $($dependency.Name) as it's already at the maximum version"
continue
}
Retry-Command -ScriptBlock {
$latestVersion = Get-LatestPypiVersion -packageId $dependency.Name
$latestVersion = Get-LatestPypiVersion -packageId (Get-QueryName -dependency $dependency)
Write-Information "Updating $($dependency.Name) from $($dependency.Version) to $latestVersion"
$dependency.Version = $latestVersion
}
}
}
elseif ($languageName -eq "Ruby") {
foreach ($dependency in $language.Dependencies) {
if ($null -ne $dependency.MaximumVersion -and $dependency.MaximumVersion -eq $dependency.Version) {
Write-Information "Skipping $($dependency.Name) as it's already at the maximum version"
continue
}
Retry-Command -ScriptBlock {
$latestVersion = Get-LatestRubygemVersion -packageId $dependency.Name
$latestVersion = Get-LatestRubygemVersion -packageId (Get-QueryName -dependency $dependency)
Write-Information "Updating $($dependency.Name) from $($dependency.Version) to $latestVersion"
$dependency.Version = $latestVersion
}
Expand All @@ -180,5 +215,5 @@ foreach ($languageName in ($appSettings.Languages | Get-Member -MemberType NoteP
}

# Write the updated appsettings.json file
$appSettings | ConvertTo-Json -Depth 100 | Set-Content -Path $mainSettings
$appSettings | ConvertTo-Json -Depth 100 | Set-Content -Path $mainSettings -NoNewLine

25 changes: 25 additions & 0 deletions src/Kiota.Builder/LanguageInformation.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
using Kiota.Builder.Extensions;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
Expand Down Expand Up @@ -72,13 +73,23 @@ public record LanguageDependency : IOpenApiSerializable
{
public string Name { get; set; } = string.Empty;
public string Version { get; set; } = string.Empty;
[JsonPropertyName("Type")]
public DependencyType? DependencyType
{
get; set;
}
private const string TypePropertyName = "type";
public void SerializeAsV2(IOpenApiWriter writer) => SerializeAsV3(writer);
public void SerializeAsV3(IOpenApiWriter writer)
{
ArgumentNullException.ThrowIfNull(writer);
writer.WriteStartObject();
writer.WriteProperty(nameof(Name).ToFirstCharacterLowerCase(), Name);
writer.WriteProperty(nameof(Version).ToFirstCharacterLowerCase(), Version);
if (DependencyType is not null)
{
writer.WriteProperty(TypePropertyName, DependencyType.ToString());
}
writer.WriteEndObject();
}
public static LanguageDependency Parse(IOpenApiAny source)
Expand All @@ -93,6 +104,10 @@ public static LanguageDependency Parse(IOpenApiAny source)
{
extension.Version = versionValue.Value;
}
if (rawObject.TryGetValue(TypePropertyName, out var typeValue) && typeValue is OpenApiString typeStringValue && Enum.TryParse<DependencyType>(typeStringValue.Value, true, out var parsedTypeValue))
{
extension.DependencyType = parsedTypeValue;
}
return extension;
}
}
Expand All @@ -103,3 +118,13 @@ public enum LanguageMaturityLevel
Preview,
Stable
}

public enum DependencyType
{
Abstractions,
Serialization,
Authentication,
Http,
Bundle,
Additional
}
12 changes: 12 additions & 0 deletions src/kiota/Handlers/BaseKiotaCommandHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@
{
var httpClientHandler = new HttpClientHandler();
if (Configuration.Generation.DisableSSLValidation)
httpClientHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

Check warning on line 69 in src/kiota/Handlers/BaseKiotaCommandHandler.cs

View workflow job for this annotation

GitHub Actions / Build

Enable server certificate validation on this SSL/TLS connection (https://rules.sonarsource.com/csharp/RSPEC-4830)

Check warning on line 69 in src/kiota/Handlers/BaseKiotaCommandHandler.cs

View workflow job for this annotation

GitHub Actions / Build

Enable server certificate validation on this SSL/TLS connection (https://rules.sonarsource.com/csharp/RSPEC-4830)

var httpClient = new HttpClient(httpClientHandler);

Check warning on line 71 in src/kiota/Handlers/BaseKiotaCommandHandler.cs

View workflow job for this annotation

GitHub Actions / Build

Rename 'httpClient' which hides the property with the same name. (https://rules.sonarsource.com/csharp/RSPEC-1117)

Check warning on line 71 in src/kiota/Handlers/BaseKiotaCommandHandler.cs

View workflow job for this annotation

GitHub Actions / Build

Rename 'httpClient' which hides the property with the same name. (https://rules.sonarsource.com/csharp/RSPEC-1117)

disposables.Add(httpClientHandler);
disposables.Add(httpClient);
Expand Down Expand Up @@ -325,6 +325,18 @@
DisplayHint("Hint: use the info command to get the list of dependencies you need to add to your project.",
$"Example: kiota info {sourceArg} -l {language}");
}
protected void DisplayDependenciesHint(GenerationLanguage generationLanguage)
{
DisplayHint("Legend:",
"- Abstractions dependencies define the core concepts of the language. Required at build time.",
"- Authentication dependencies implement authentication providers. Optional at runtime.",
"- Additional dependencies are required in addition to the abstractions or bundle. Required at build time.",
"- Bundle dependencies include abstractions, serialization and HTTP dependencies for simpler management.",
"- HTTP dependencies implement the request adapter with a specific HTTP client. Required at runtime.",
"- Serialization dependencies implement serialization and deserialization for a given format. Required at runtime.");
DisplayHint("Hint: use the --dependency-type argument to filter the dependencies by type.",
$"Example: kiota info -l {generationLanguage} --dependency-type serialization");
}
protected void DisplayInstallHint(LanguageInformation languageInformation, List<LanguageDependency> languageDependencies)
{
if (!string.IsNullOrEmpty(languageInformation.DependencyInstallCommand) && languageDependencies.Count > 0)
Expand Down
25 changes: 21 additions & 4 deletions src/kiota/Handlers/KiotaInfoCommandHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
{
get; init;
}
public required Option<DependencyType[]> DependencyTypesOption
{
get; init;
}

public override async Task<int> InvokeAsync(InvocationContext context)
{
Expand All @@ -48,6 +52,7 @@
string searchTerm = context.ParseResult.GetValueForOption(SearchTermOption) ?? string.Empty;
string version = context.ParseResult.GetValueForOption(VersionOption) ?? string.Empty;
bool json = context.ParseResult.GetValueForOption(JsonOption);
DependencyType[] dependencyTypes = context.ParseResult.GetValueForOption(DependencyTypesOption) ?? [];
GenerationLanguage? language = context.ParseResult.GetValueForOption(GenerationLanguage);
CancellationToken cancellationToken = context.BindingContext.GetService(typeof(CancellationToken)) is CancellationToken token ? token : CancellationToken.None;
var (loggerFactory, logger) = GetLoggerAndFactory<KiotaBuilder>(context);
Expand Down Expand Up @@ -85,17 +90,17 @@
if (result != null)
instructions = result;
}
catch (Exception ex)

Check warning on line 93 in src/kiota/Handlers/KiotaInfoCommandHandler.cs

View workflow job for this annotation

GitHub Actions / Build

Either log this exception and handle it, or rethrow it with some contextual information. (https://rules.sonarsource.com/csharp/RSPEC-2139)

Check warning on line 93 in src/kiota/Handlers/KiotaInfoCommandHandler.cs

View workflow job for this annotation

GitHub Actions / Build

Either log this exception and handle it, or rethrow it with some contextual information. (https://rules.sonarsource.com/csharp/RSPEC-2139)
{
#if DEBUG
logger.LogCritical(ex, "error getting information from the description: {exceptionMessage}", ex.Message);

Check warning on line 96 in src/kiota/Handlers/KiotaInfoCommandHandler.cs

View workflow job for this annotation

GitHub Actions / Build

Use PascalCase for named placeholders. (https://rules.sonarsource.com/csharp/RSPEC-6678)
throw; // so debug tools go straight to the source of the exception when attached
#else
logger.LogCritical("error getting information from the description: {exceptionMessage}", ex.Message);
return 1;
#endif
}
ShowLanguageInformation(language.Value, instructions, json);
ShowLanguageInformation(language.Value, instructions, json, dependencyTypes);
return 0;
}
}
Expand All @@ -113,7 +118,7 @@
var layout = new StackLayoutView { view };
console.Append(layout);
}
private void ShowLanguageInformation(GenerationLanguage language, LanguagesInformation informationSource, bool json)
private void ShowLanguageInformation(GenerationLanguage language, LanguagesInformation informationSource, bool json, DependencyType[] dependencyTypes)
{
if (informationSource.TryGetValue(language.ToString(), out var languageInformation))
{
Expand All @@ -122,17 +127,29 @@
DisplayInfo($"The language {language} is currently in {languageInformation.MaturityLevel} maturity level.",
"After generating code for this language, you need to install the following packages:");
var orderedDependencies = languageInformation.Dependencies.OrderBy(static x => x.Name).Select(static x => x).ToList();
var filteredDependencies = (dependencyTypes.ToHashSet(), orderedDependencies.Any(static x => x.DependencyType is DependencyType.Bundle)) switch

Check warning on line 130 in src/kiota/Handlers/KiotaInfoCommandHandler.cs

View workflow job for this annotation

GitHub Actions / Build

Collection-specific "Exists" method should be used instead of the "Any" extension. (https://rules.sonarsource.com/csharp/RSPEC-6605)
{
//if the user requested a specific type, we filter the dependencies
({ Count: > 0 }, _) => orderedDependencies.Where(x => x.DependencyType is null || dependencyTypes.Contains(x.DependencyType.Value)).ToList(),
//otherwise we display only the bundle dependencies
(_, true) => orderedDependencies.Where(static x => x.DependencyType is DependencyType.Bundle or DependencyType.Authentication or DependencyType.Additional).ToList(),
//otherwise we display all dependencies
_ => orderedDependencies
};
var view = new TableView<LanguageDependency>()
{
Items = orderedDependencies,
Items = filteredDependencies,
};
view.AddColumn(static x => x.Name, "Package Name");
view.AddColumn(static x => x.Version, "Version");
if (orderedDependencies.Any(static x => x.DependencyType is not null))

Check warning on line 145 in src/kiota/Handlers/KiotaInfoCommandHandler.cs

View workflow job for this annotation

GitHub Actions / Build

Collection-specific "Exists" method should be used instead of the "Any" extension. (https://rules.sonarsource.com/csharp/RSPEC-6605)
view.AddColumn(static x => x.DependencyType?.ToString(), "Type");
var console = new SystemConsole();
using var terminal = new SystemConsoleTerminal(console);
var layout = new StackLayoutView { view };
console.Append(layout);
DisplayInstallHint(languageInformation, orderedDependencies);
DisplayDependenciesHint(language);
DisplayInstallHint(languageInformation, filteredDependencies);
}
else
{
Expand Down
1 change: 1 addition & 0 deletions src/kiota/KiotaConfigurationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
/// </summary>
/// <param name="configObject">The configuration object to bind to</param>
/// <param name="configuration">The configuration to bind from</param>
public static void BindConfiguration(this KiotaConfiguration configObject, IConfigurationRoot configuration)

Check warning on line 16 in src/kiota/KiotaConfigurationExtensions.cs

View workflow job for this annotation

GitHub Actions / Build

Refactor this method to reduce its Cognitive Complexity from 36 to the 15 allowed. (https://rules.sonarsource.com/csharp/RSPEC-3776)
{
ArgumentNullException.ThrowIfNull(configObject);
ArgumentNullException.ThrowIfNull(configuration);
Expand Down Expand Up @@ -45,6 +45,7 @@
{
Version = dependency[nameof(LanguageDependency.Version)] ?? string.Empty,
Name = dependency[nameof(LanguageDependency.Name)] ?? string.Empty,
DependencyType = dependency["Type"] is string typeValue && !string.IsNullOrEmpty(typeValue) && Enum.TryParse<DependencyType>(typeValue, true, out var dt) ? dt : null,
});
}
configObject.Languages.Add(section.Key, lngInfo);
Expand Down
15 changes: 15 additions & 0 deletions src/kiota/KiotaHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ private static Command GetInfoCommand()
var clearCacheOption = GetClearCacheOption(defaultGenerationConfiguration.ClearCache);
var searchTermOption = GetSearchKeyOption();
var languageOption = new Option<GenerationLanguage?>("--language", "The target language for the dependencies instructions.");
var dependencyTypesOption = GetDependencyTypesOption();
var jsonOption = new Option<bool>("--json", "Generate a plain and machine-parsable json output.");
languageOption.AddAlias("-l");
AddEnumValidator(languageOption, "language");
Expand All @@ -120,6 +121,7 @@ private static Command GetInfoCommand()
searchTermOption,
languageOption,
jsonOption,
dependencyTypesOption,
};
infoCommand.Handler = new KiotaInfoCommandHandler
{
Expand All @@ -131,9 +133,22 @@ private static Command GetInfoCommand()
SearchTermOption = searchTermOption,
GenerationLanguage = languageOption,
JsonOption = jsonOption,
DependencyTypesOption = dependencyTypesOption,
};
return infoCommand;
}
private static Option<DependencyType[]> GetDependencyTypesOption()
{
var dependencyTypesOption = new Option<DependencyType[]>("--dependency-type", "The type of dependency to display instructions for.")
{
IsRequired = false,
Arity = ArgumentArity.ZeroOrMore,
};
dependencyTypesOption.AddAlias("--dt");
dependencyTypesOption.SetDefaultValue(Array.Empty<DependencyType>());
dependencyTypesOption.AddCompletions(Enum.GetNames<DependencyType>());
return dependencyTypesOption;
}
private static Option<string> GetSearchKeyOption()
{
var option = new Option<string>("--search-key", () => string.Empty, "The API search key to display the description for. Use the search command to get the key.");
Expand Down
Loading
Loading