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

Configuration Schema generator #1383

Merged
merged 21 commits into from
Dec 15, 2023
Merged

Conversation

eerhardt
Copy link
Member

@eerhardt eerhardt commented Dec 13, 2023

Adds a tool that automatically generates ConfigurationSchema.json files for components.

To use the tool, a component adds an assembly attribute. For example:

[assembly: ConfigurationSchema("Aspire:Azure:Storage:Blobs", typeof(AzureStorageBlobsSettings))]
[assembly: ConfigurationSchema("Aspire:Azure:Storage:Blobs:ClientOptions", typeof(BlobClientOptions), exclusionPaths: ["Default"])]

[assembly: LoggingCategories("Azure", "Azure.Core", "Azure.Identity")]

ConfigurationSchemaAttribute

  • The first parameter is the config section path where the type is loaded from.
  • The second parameter is the Type that is bound at that path.
  • ExclusionPaths - (optional) The config sections to exclude from the ConfigurationSchema. This is useful if there are properties you don't want to publicize in the config schema.

LoggingCategoriesAttribute

  • The list of log categories produced by the component. These categories will show up under the Logging section in appsettings.json

This tool works after compilation by scanning the assembly for ConfigurationSchema and LoggingCategories attributes, and uses Roslyn APIs to inspect all properties of the types. It reuses all the parsing logic from https://github.com/dotnet/runtime/tree/main/src/libraries/Microsoft.Extensions.Configuration.Binder/gen, and using the underlying model objects, generates a JSON schema using System.Text.Json.Nodes APIs.

I've copied the necessary code from dotnet/runtime into the RuntimeSource folder for now. This code doesn't need to be reviewed since it is a straight copy from dotnet/runtime. After this PR goes through, we will set up an automatic "sync" action that will update this code anytime changes in the dotnet/runtime code is updated.

The remaining work to address after the initial PR:

  • Supporting collection/enumerable properties (skipped for now)
  • Perf: the tool takes ~400-500 ms to run. An option we should try is to load the Roslyn assemblies from the SDK, which are already R2R'd. This may make the tool faster because it won't need to JIT Roslyn every time it is run. This would be the same logic used in Improve loading of Roslyn assemblies on validate package task sdk#22277.

cc @eiriktsarpalis @tarekgh

Fix #1146

Microsoft Reviewers: Open in CodeFlow

Use XDcoument to parse the doc comments.
Strip xml elements from summary, strip new lines, and escape invalid chars.
Skip properties that are obsolete, editorbrowsable(never), or not settable.

Support Uris.
Fix doc comments on the root objects - use the Type's summary.
…hey don't match.

Add an option to update the checked in file.
Remove unnecessary attributes.
Ensure Specs folder matches runtime code.
Ensure Roslyn and SourceGenerators common folders match runtime code.
Use the Parser from dotnet/runtime and inject more methods into it using the partial class.
Mock out the DiagnosticDescriptors because we don't need localization.
@dotnet-issue-labeler dotnet-issue-labeler bot added the area-integrations Issues pertaining to Aspire Integrations packages label Dec 13, 2023
<PropertyGroup>

<GeneratorCommandLine>"$(DotNetTool)" exec $(ConfigurationSchemaGeneratorPath)</GeneratorCommandLine>
<GeneratorCommandLine>$(GeneratorCommandLine) --input "@(IntermediateAssembly)"</GeneratorCommandLine>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't looked at it in a while, but TargetsTriggeredByCompilation is guaranteed to be called after CoreCompile, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. See https://github.com/dotnet/roslyn/blob/5249865bc562b64333ae80de6ccb47e7881b7840/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets#L84-L173

Whenever CoreCompile runs Csc, it will <CallTarget Targets="$(TargetsTriggeredByCompilation)"

},
"GeoRedundantSecondaryUri": {
"type": "string",
"format": "uri",
"description": "Gets or sets the secondary storage Uri that can be read from for the storage account if the account is enabled for RA-GRS."
"description": "Gets or sets the secondary storage T:System.Uri that can be read from for the storage account if the\r\n account is enabled for RA-GRS.\r\n \r\n If this property is set, the secondary Uri will be used for GET or HEAD requests during retries.\r\n If the status of the response from the secondary Uri is a 404, then subsequent retries for\r\n the request will not use the secondary Uri again, as this indicates that the resource\r\n may not have propagated there yet. Otherwise, subsequent retries will alternate back and forth\r\n between primary and secondary Uri."
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, I'm curious, how does this render in the IDE, I suppose it actually shows the new lines as opposed to having the new line characters printed out?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It renders the newlines correctly. This is an area that will probably need to be tweaked over time. I don't know why the newlines and extra spaces are in there. I need to look at some more Roslyn code to figure out how they strip out all the whitespace in these XML docs.

image


</Target>

<Target Name="CompareConfigurationSchema"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it supposed to be where the logic to verify the json file that is committed in the repos is up to date with the curent code?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct.

Refactor attributes to be more understandable and easier to use.
@eerhardt eerhardt merged commit 4794d39 into dotnet:main Dec 15, 2023
8 checks passed
@eerhardt eerhardt deleted the ConfigSchemaGenerator branch December 15, 2023 20:19
stephentoub pushed a commit to dotnet/runtime that referenced this pull request Jan 2, 2024
The TypeParseInfo.BinderInvocation is a nullable property. If it happens to be null, these two places will throw a null ref.

.NET Aspire is reusing this code to generate JSON schemas for appsettings.json files. See dotnet/aspire#1383. The plan is to keep this in sync using automated PRs to dotnet/aspire when the dotnet/runtime code is updated. (dotnet/aspire#1424). Contributing this fix back so these two code bases can stay in sync.
@eerhardt eerhardt mentioned this pull request Jan 9, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Apr 27, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-integrations Issues pertaining to Aspire Integrations packages
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Automatic generation of ConfigurationSchema.json files
3 participants