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

Split library and package Readme #78888

Merged
merged 11 commits into from
Dec 12, 2022
29 changes: 18 additions & 11 deletions docs/coding-guidelines/libraries-packaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,29 @@ Libraries to be packaged must set `IsPackable` to true. By default, all `librari

Package versions and shipping state should be controlled using the properties defined by the [Arcade SDK](https://github.com/dotnet/arcade/blob/master/Documentation/ArcadeSdk.md#project-properties-defined-by-the-sdk). Typically libraries should not need to explicitly set any of these properties.

Most metadata for packages is controlled centrally in the repository and individual projects may not need to make any changes to these. One property is required to be set in each project: `PackageDescription`. This should be set to a descriptive summary of the purpose of the package, and a list of common entry-point types for the package: to aide in search engine optimization. Example:
Most metadata for packages is controlled centrally in the repository and individual projects may not need to make any changes to these. One property is required to be set in each project: `PackageDescription`. This should be set to a descriptive summary of the purpose of the package. Example:

```xml
<PackageDescription>Logging abstractions for Microsoft.Extensions.Logging.

Commonly Used Types:
Microsoft.Extensions.Logging.ILogger
Microsoft.Extensions.Logging.ILoggerFactory
Microsoft.Extensions.Logging.ILogger&lt;TCategoryName&gt;
Microsoft.Extensions.Logging.LogLevel
Microsoft.Extensions.Logging.Logger&lt;T&gt;
Microsoft.Extensions.Logging.LoggerMessage
Microsoft.Extensions.Logging.Abstractions.NullLogger</PackageDescription>
<PackageDescription>Logging abstractions for Microsoft.Extensions.Logging.</PackageDescription>
```

Package content can be defined using any of the publicly defined Pack inputs: https://docs.microsoft.com/en-us/nuget/reference/msbuild-targets

### Package Readme

Packages can include a Markdown Readme file with a short usage documentation. To include a package Readme, create a `PACKAGE.md` file in the library `src` directory. The file will be automatically included in the package and used as a Readme if its name matches this convention.

The package Readme is displayed on the package details page on [NuGet gallery](https://nuget.org/). You can include the following content in it:

- A description of the package purpose.
- Information when package should be used. For example, if the library is included in the shared framework in .NET, but needs to be isntalled via NuGet in .NET Framework, it should be mentioned.
ViktorHofer marked this conversation as resolved.
Show resolved Hide resolved
- Information on how to get started with the package.
- Links to related documentation.
- A list of common entry-point types for the package, with links to their API docs under [.NET API Browser](https://learn.microsoft.com/dotnet/api/).
- A short code example that demostrates the package usage.

For a list of supported Markdown features, see [NuGet documentation](https://learn.microsoft.com/nuget/nuget-org/package-readme-on-nuget-org#supported-markdown-features).

### Build props / targets and other content

Build props and targets may be needed in NuGet packages. To define these, author a build folder in your src project and place the necessary props/targets in this subfolder. You can then add items to include these in the package by defining `Content` items and setting `PackagePath` as follows:
Expand Down
6 changes: 6 additions & 0 deletions eng/packaging.targets
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<!-- Don't include target platform specific dependencies, since we use the target platform to represent RIDs instead -->
<SuppressDependenciesWhenPacking Condition="'$(TargetPlatformIdentifier)' != ''">true</SuppressDependenciesWhenPacking>
<PackageDesignerMarkerFile>$(MSBuildThisFileDirectory)useSharedDesignerContext.txt</PackageDesignerMarkerFile>
<PackageReadmeFile Condition="'$(PackageReadmeFile)' == '' and Exists('PACKAGE.md')">PACKAGE.md</PackageReadmeFile>
Copy link
Member

Choose a reason for hiding this comment

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

Maybe the file name could be PACKAGE_README.md? PACKAGE.md doesn't really describe exactly what the file is.

Copy link
Member

Choose a reason for hiding this comment

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

When it comes to NuGet Gallery, the PACKAGE.md file is automatically respected and displayed as the package's nuspec encodes it. Personally, I'm fine with the PACKAGE.md name and I don't think it's common that a dev crack opens a nuget package in order to understand how to use it.

Copy link
Member

Choose a reason for hiding this comment

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

It's more about readability/understandability of the files in the repo.

Copy link
Member

Choose a reason for hiding this comment

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

Other options include:

  1. PackageReadme.md
  2. The file under a docs folder, and still name it README.md. e.g. src/docs/README.md
  3. Since the files are split already - one is in the root of the library, and one is under src - they could both be named README.md.

Copy link
Contributor Author

@MSDN-WhiteKnight MSDN-WhiteKnight Nov 28, 2022

Choose a reason for hiding this comment

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

The PACKAGE.md choice was based on this suggestion: #59630 (comment) I don't think this name needs to be long as there's not a lot of .md files in folder to disambiguate between them. So personally i'd prefer either README.md or PACKAGE.md.

Copy link
Member

@ViktorHofer ViktorHofer Nov 28, 2022

Choose a reason for hiding this comment

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

Being able to distinguish between a package documentation file and a repo specific contribution guidance seems valuable to me. We unintentionally started shipping the contribution guidance files to customers and this PR fixes that: #59630 (comment).

<!-- Generate packages for rid specific projects or for allconfigurations during build. -->
<!-- A package isn't generated if in servicing or in runtimelab. Intended to be overridden at project level. -->
<IsRIDSpecificProject Condition="$(MSBuildProjectName.StartsWith('runtime.')) and
Expand Down Expand Up @@ -57,6 +58,11 @@
TargetFramework="$(NetFrameworkMinimum)" />
</ItemGroup>

<!-- Add a package README file from. -->
<ItemGroup Condition="'$(PackageReadmeFile)' != ''">
<None Include="$(PackageReadmeFile)" Pack="true" PackagePath="\" />
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
<None Include="$(PackageReadmeFile)" Pack="true" PackagePath="\" />
<None Include="$(PackageReadmeFile)" Pack="true" PackagePath="README.md" />

You want the file to be named README.md, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don't have to specify name README.md, NuGet will recognize any name set by PackageReadmeFile property. Also PackagePath seems to be a path without name, it is used like that in docs: https://learn.microsoft.com/en-us/nuget/reference/msbuild-targets#packagereadmefile

</ItemGroup>

<Choose>
<When Condition="'$(AddXamarinPlaceholderFilesToPackage)' == 'true' or '$(AddNETFrameworkPlaceholderFileToPackage)' == 'true'">
<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
# Microsoft.Extensions.Configuration.Abstractions

Provides abstractions of key-value pair based configuration. Interfaces defined in this package are implemented by classes in [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/) and other configuration packages.

Commonly used types:

- [Microsoft.Extensions.Configuration.IConfiguration](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfiguration)
- [Microsoft.Extensions.Configuration.IConfigurationBuilder](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationbuilder)
- [Microsoft.Extensions.Configuration.IConfigurationProvider](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationprovider)
- [Microsoft.Extensions.Configuration.IConfigurationRoot](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationroot)
- [Microsoft.Extensions.Configuration.IConfigurationSection](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationsection)
Provides abstractions of key-value pair based configuration.

Documentation can be found at https://learn.microsoft.com/dotnet/core/extensions/configuration

Expand Down Expand Up @@ -41,7 +33,7 @@ Console.WriteLine(options.NamedProperty); // returns "value for named property"
```

## Contribution Bar
- [x] [We consider new features, new APIs, bug fixes, and performance changes](https://github.com/dotnet/runtime/tree/main/src/libraries#contribution-bar)
- [x] [We consider new features, new APIs, bug fixes, and performance changes](../README.md#contribution-bar)

The APIs and functionality are mature, but do get extended occasionally.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
<EnableDefaultItems>true</EnableDefaultItems>
<IsPackable>true</IsPackable>
<EnableAOTAnalyzer>true</EnableAOTAnalyzer>
<IsPackable>true</IsPackable>
<PackageDescription>Provides abstractions of key-value pair based configuration. Interfaces defined in this package are implemented by classes in Microsoft.Extensions.Configuration and other configuration packages.</PackageDescription>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="$(LibrariesProjectRoot)Microsoft.Extensions.Primitives\src\Microsoft.Extensions.Primitives.csproj" />
<Compile Include="$(CommonPath)System\ThrowHelper.cs"
Link="Common\System\ThrowHelper.cs" />
<None Include="..\README.md" Pack="true" PackagePath="\"/>
</ItemGroup>

<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
## About

Provides abstractions of key-value pair based configuration. Interfaces defined in this package are implemented by classes in [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/) and other configuration packages.

Commonly used types:

- [Microsoft.Extensions.Configuration.IConfiguration](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfiguration)
- [Microsoft.Extensions.Configuration.IConfigurationBuilder](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationbuilder)
- [Microsoft.Extensions.Configuration.IConfigurationProvider](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationprovider)
- [Microsoft.Extensions.Configuration.IConfigurationRoot](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationroot)
- [Microsoft.Extensions.Configuration.IConfigurationSection](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationsection)

For more information, see the documentation: [Configuration in .NET](https://learn.microsoft.com/dotnet/core/extensions/configuration).

## Example

The example below shows a small code sample using this library and trying out the `ConfigurationKeyName` attribute available since .NET 6:

```cs
public class MyClass
{
[ConfigurationKeyName("named_property")]
public string NamedProperty { get; set; }
}
```

Given the simple class above, we can create a dictionary to hold the configuration data and use it as the memory source to build a configuration section:

```cs
var dic = new Dictionary<string, string>
{
{"named_property", "value for named property"},
};

var config = new ConfigurationBuilder()
.AddInMemoryCollection(dic)
.Build();

var options = config.Get<MyClass>();
Console.WriteLine(options.NamedProperty); // returns "value for named property"
```
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Microsoft.Extensions.Configuration.Binder

Provides the functionality to bind an object to data in configuration providers for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). This package enables you to represent the configuration data as strongly-typed classes defined in the application code. To bind a configuration, use the [Microsoft.Extensions.Configuration.ConfigurationBinder.Get](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.configurationbinder.get) extension method on the `IConfiguration` object. To use this package, you also need to install a package for the [configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration#configuration-providers), for example, [Microsoft.Extensions.Configuration.Json](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Json/) for the JSON provider.
Provides the functionality to bind an object to data in configuration providers for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/).

Documentation can be found at https://learn.microsoft.com/dotnet/core/extensions/configuration

## Contribution Bar
- [x] [We consider new features, new APIs, bug fixes, and performance changes](https://github.com/dotnet/runtime/tree/main/src/libraries#contribution-bar)
- [x] [We consider new features, new APIs, bug fixes, and performance changes](../README.md#contribution-bar)

The APIs and functionality are mature, but do get extended occasionally.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@
<IsPackable>true</IsPackable>
<EnableAOTAnalyzer>true</EnableAOTAnalyzer>
<PackageDescription>Provides the functionality to bind an object to data in configuration providers for Microsoft.Extensions.Configuration. This package enables you to represent the configuration data as strongly-typed classes defined in the application code. To bind a configuration, use the Microsoft.Extensions.Configuration.ConfigurationBinder.Get extension method on the IConfiguration object. To use this package, you also need to install a package for the configuration provider, for example, Microsoft.Extensions.Configuration.Json for the JSON provider.</PackageDescription>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="$(LibrariesProjectRoot)Microsoft.Extensions.Configuration.Abstractions\src\Microsoft.Extensions.Configuration.Abstractions.csproj" />
<Compile Include="$(CommonPath)Extensions\ParameterDefaultValue\ParameterDefaultValue.cs" Link="Common\src\Extensions\ParameterDefaultValue\ParameterDefaultValue.cs" />
<Compile Include="$(CommonPath)System\ThrowHelper.cs" Link="Common\System\ThrowHelper.cs" />
<None Include="..\README.md" Pack="true" PackagePath="\"/>
</ItemGroup>

<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
## About

Provides the functionality to bind an object to data in configuration providers for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). This package enables you to represent the configuration data as strongly-typed classes defined in the application code. To bind a configuration, use the [Microsoft.Extensions.Configuration.ConfigurationBinder.Get](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.configurationbinder.get) extension method on the `IConfiguration` object. To use this package, you also need to install a package for the [configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration#configuration-providers), for example, [Microsoft.Extensions.Configuration.Json](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Json/) for the JSON provider.

For more information, see the documentation: [Configuration in .NET](https://learn.microsoft.com/dotnet/core/extensions/configuration).

## Example
The following example shows how to bind a JSON configuration section to .NET objects.

```cs
using System;
using Microsoft.Extensions.Configuration;

class Settings
{
public string Server { get; set; }
public string Database { get; set; }
public Endpoint[] Endpoints { get; set; }
}

class Endpoint
{
public string IPAddress { get; set; }
public int Port { get; set; }
}

class Program
{
static void Main()
{
// Build a configuration object from JSON file
IConfiguration config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();

// Bind a configuration section to an instance of Settings class
Settings settings = config.GetSection("Settings").Get<Settings>();

// Read simple values
Console.WriteLine($"Server: {settings.Server}");
Console.WriteLine($"Database: {settings.Database}");

// Read nested objects
Console.WriteLine("Endpoints: ");

foreach (Endpoint endpoint in settings.Endpoints)
{
Console.WriteLine($"{endpoint.IPAddress}:{endpoint.Port}");
}
}
}
```

To run this example, include an `appsettings.json` file with the following content in your project:

```json
{
"Settings": {
"Server": "example.com",
"Database": "Northwind",
"Endpoints": [
{
"IPAddress": "192.168.0.1",
"Port": "80"
},
{
"IPAddress": "192.168.10.1",
"Port": "8080"
}
]
}
}
```

You can include a configuration file using a code like this in your `.csproj` file:

```xml
<ItemGroup>
<Content Include="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
```
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Microsoft.Extensions.Configuration.CommandLine

Command line configuration provider implementation for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). This package enables you to read configuration parameters from the command line arguments of your application. You can use [CommandLineConfigurationExtensions.AddCommandLine](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.commandlineconfigurationextensions.addcommandline) extension method on `IConfigurationBuilder` to add the command line configuration provider to the configuration builder.
Command line configuration provider implementation for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/).

Documentation can be found at https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#command-line-configuration-provider

## Contribution Bar
- [x] [We consider new features, new APIs, bug fixes, and performance changes](https://github.com/dotnet/runtime/tree/main/src/libraries#contribution-bar)
- [x] [We consider new features, new APIs, bug fixes, and performance changes](../README.md#contribution-bar)

The APIs and functionality are mature, but do get extended occasionally.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@
<IsPackable>true</IsPackable>
<EnableAOTAnalyzer>true</EnableAOTAnalyzer>
<PackageDescription>Command line configuration provider implementation for Microsoft.Extensions.Configuration. This package enables you to read configuration parameters from the command line arguments of your application. You can use CommandLineConfigurationExtensions.AddCommandLine extension method on IConfigurationBuilder to add the command line configuration provider to the configuration builder.</PackageDescription>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="$(LibrariesProjectRoot)Microsoft.Extensions.Configuration\src\Microsoft.Extensions.Configuration.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)Microsoft.Extensions.Configuration.Abstractions\src\Microsoft.Extensions.Configuration.Abstractions.csproj" />
<Compile Include="$(CommonPath)System\ThrowHelper.cs"
Link="Common\System\ThrowHelper.cs" />
<None Include="..\README.md" Pack="true" PackagePath="\"/>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
## About

Command line configuration provider implementation for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). This package enables you to read configuration parameters from the command line arguments of your application. You can use [CommandLineConfigurationExtensions.AddCommandLine](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.commandlineconfigurationextensions.addcommandline) extension method on `IConfigurationBuilder` to add the command line configuration provider to the configuration builder.

For more information, see the documentation: [Command-line configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#command-line-configuration-provider).

## Example

The following example shows how to read application configuration from the command line. You can use a command like `dotnet run --InputPath "c:\fizz" --OutputPath "c:\buzz"` to run it.

```cs
using System;
using Microsoft.Extensions.Configuration;

class Program
{
static void Main(string[] args)
{
// Build a configuration object from command line
IConfiguration config = new ConfigurationBuilder()
.AddCommandLine(args)
.Build();

// Read configuration values
Console.WriteLine($"InputPath: {config["InputPath"]}");
Console.WriteLine($"OutputPath: {config["OutputPath"]}");
}
}
```
Loading