ApiSurface 3.0.10

There is a newer version of this package available.
See the version list below for details.
dotnet add package ApiSurface --version 3.0.10                
NuGet\Install-Package ApiSurface -Version 3.0.10                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ApiSurface" Version="3.0.10" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add ApiSurface --version 3.0.10                
#r "nuget: ApiSurface, 3.0.10"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install ApiSurface as a Cake Addin
#addin nuget:?package=ApiSurface&version=3.0.10

// Install ApiSurface as a Cake Tool
#tool nuget:?package=ApiSurface&version=3.0.10                

ApiSurface

This library provides several modules for ensuring the consistency and documentation coverage of an F# assembly's public API.

How to get started

  1. Create an empty SurfaceBaseline.txt file next to your assembly's .fsproj file. (.csproj files are not officially supported, but have been observed to work.)
  2. Add an <EmbeddedResource Include="SurfaceBaseline.txt" /> entry to that .fsproj file.
  3. Following the example of this repository's ApiSurface.Test.TestSurface, create tests as follows:
    namespace MyLibrary.Test
    
    open NUnit.Framework
    open ApiSurface
    open MyLibrary
    
    [<TestFixture>]
    module TestSurface =
    
        let assembly = typeof<TypeFromMyLibrary>.Assembly
    
        [<Test>]
        let ``Ensure API surface has not been modified`` () =
            ApiSurface.assertIdentical assembly
    
        [<Test; Explicit>]
        let ``Update API surface`` () =
            ApiSurface.writeAssemblyBaseline assembly
    
        [<Test>]
        let ``Ensure public API is fully documented`` () =
            DocCoverage.assertFullyDocumented assembly
    
        [<Test>]
        let ``Ensure version is monotonic`` () =
            MonotonicVersion.validate assembly "NuGet.PackageName"
    
  4. Run the Explicit test called Update API surface, to populate the empty SurfaceBaseline.txt file you made earlier.
  5. Similarly, place a version.json file next to your project, using the NerdBank.GitVersioning format, and include it as an EmbeddedResource.
  6. Run the Ensure version is monotonic test, to check that your version.json file correctly specifies a version number which is valid with respect to the current release of your NuGet package.

The modules of ApiSurface

ApiSurface module

The ApiSurface module enforces that the public API surface does not change. The public API is serialised in a 'SurfaceBaseline.txt' file that is embedded in the assembly. Unit tests can then ensure that the API surface of the assembly under test matches that which is encoded in the baseline text file.

You can use ApiSurface.writeAssemblyBaseline to manually update the SurfaceBaseline.txt file. Common practice is to call this function inside a unit test which is marked Explicit - this ensures that the public API is easy to update with a single click, but that it is not accidentally extended (or reduced) simply by running your normal tests.

DocCoverage module

The DocCoverage module provides a function to ensure that the entirety of the public API surface is documented. Note that there are some exceptions to this rule:

  • Class constructors never need to be documented. These tend to never be more useful than 'Instantiates the type' anyway.
  • All discriminated union case constructors have to be documented.
  • Modules which have the same name as a type do not have to be documented. It is self-explanatory that the module simply contains function that construct/act upon the type they are named after.

It is possible to explicitly annotate a type or member as not needing documentation by adding the [<Undocumented>] attribute. When applied to a type, all members of that type inherit the [<Undocumented>] attribute. This can be overridden with [<Undocumented(MembersInherit=false)>].

MonotonicVersion module

The MonotonicVersion module provides a function to ensure that the version field in the version.json file is always increasing. This check can fail if a change which increments the major or minor version is reverted.

Semantic Versioning

Along with monitoring a project's public API, this library can be used to encourage semantic versioning. When running the explicit test (see below) to update a project's SurfaceBaseline file, the test will also look for a version.json file (in the same location as the SurfaceBaseline file). If the version.json file is not found, an error will be raised. If the version.json file is found, the version.json file will be updated with a newer version using the following logic (from https://semver.org/):

  • MAJOR version is incremented when backwards incompatible API changes are detected (i.e. API memebers are changed or removed)
  • MINOR version is incremented when added backwards-compatible functionality changes are detected (i.e. API members are added only)

If no API changes are detected, the version will not be incremented by the test. If you are using NerdBank.GitVersioning then the PATCH version will be incremented as required for any change, in combination with the above.

Important! This isn't intended to replace a real human thinking about the version number. Breaking behaviour changes (without API changes) still require a major version bump, but no tool can make this judgement for you; ApiSurface only detects the most obvious cases, where the API surface has changed.

There are not any currently known changes you can make to the API surface of your library that "should" be recognisably major version bumps but which do not result in ApiSurface flagging the change. Please raise an issue if you find one.

Different API surfaces on different frameworks

ApiSurface supports the rare situation of APIs which are different between .NET Framework and .NET Core, or between different versions of the .NET runtime. Instead of giving the default SurfaceBaseline.txt file, you can override any given framework with one or more specially-named SurfaceBaseline-FRAMEWORKNAME.txt files; for example, SurfaceBaseline-Net5.txt or SurfaceBaseline-NetFramework.txt.

Note that ApiSurface.writeAssemblyBaseline will only write a SurfaceBaseline.txt, and it will only do so for the currently-executing framework. If you wish to make this specific to .NET Framework or .NET Core, you should then manually rename the file.

For the complete list of supported frameworks and file names, see the private frameworkBaselineFile : string in the ApiSurface module.

Fully worked end-to-end example

Within the project file

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
  </PropertyGroup>
  <ItemGroup>
    <EmbeddedResource Include="SurfaceBaseline.txt" />
    <EmbeddedResource Include="version.json" />
  </ItemGroup>
</Project>

If you are multi-targetting and you wish for different SurfaceBaseline.txt files for each target, you should generate SurfaceBaseline files for each target (renaming them to follow the naming schema as described in the summary of this README), and include them all in the project file.

The version.json file

Add a version.json file to the root of the project, following NerdBank.GitVersioning convention.

Within the unit test project

  1. Add a reference to ApiSurface.
  2. Then add the following files to your test project:
TestSurface.fs
namespace MyLibrary.Test

open NUnit.Framework
open ApiSurface


[<TestFixture>]
module TestSurface =

    let assembly = typeof<_ MyLibrary.SomeDefinedType>.Assembly

    [<Test>]
    let ``Ensure API surface has not been modified`` () =
        ApiSurface.assertIdentical assembly

    [<Test; Explicit>]
    let ``Update API surface`` () =
        ApiSurface.writeAssemblyBaseline assembly

    [<Test>]
    let ``Ensure public API is fully documented`` () =
        DocCoverage.assertFullyDocumented assembly

    [<Test>]
    let ``Ensure version is monotonic`` () =
        MonotonicVersion.validate assembly "MyCompany.MyLibraryNuGetPackage"
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
4.1.9 37 11/14/2024
4.1.8 377 10/21/2024
4.1.7 159 10/14/2024
4.1.6 392 10/7/2024
4.1.5 1,408 9/2/2024
4.1.4 74 8/28/2024
4.1.3 66 8/28/2024
4.1.2 245 8/21/2024
4.1.1 78 8/20/2024
4.0.44 387 8/13/2024
4.0.43 1,050 7/8/2024
4.0.42 146 7/1/2024
4.0.41 956 6/10/2024
4.0.40 2,231 5/27/2024
4.0.39 138 5/1/2024
4.0.38 41 5/1/2024
4.0.37 45 5/1/2024
4.0.36 142 4/22/2024
4.0.35 89 4/16/2024
4.0.34 71 4/15/2024
4.0.33 213 2/29/2024
4.0.32 77 2/29/2024
4.0.31 85 2/28/2024
4.0.30 226 2/19/2024
4.0.29 98 2/13/2024
4.0.28 290 2/6/2024
4.0.27 172 1/30/2024
4.0.26 72 1/30/2024
4.0.25 787 12/18/2023
4.0.24 82 12/18/2023
4.0.23 106 12/11/2023
4.0.22 94 12/11/2023
4.0.21 89 12/11/2023
4.0.20 124 11/20/2023
4.0.19 114 11/5/2023
4.0.18 122 10/23/2023
4.0.16 114 10/19/2023
4.0.15 106 10/19/2023
4.0.14 97 10/19/2023
4.0.13 102 10/19/2023
4.0.12 274 6/14/2023
4.0.11 157 5/25/2023
4.0.10 149 5/22/2023
4.0.9 136 5/22/2023
4.0.8 435 4/21/2023
4.0.7 150 4/19/2023
4.0.6 171 4/14/2023
4.0.5 210 3/16/2023
4.0.4 194 3/16/2023
4.0.3 323 12/5/2022
4.0.2 301 12/2/2022
4.0.1 309 11/30/2022
3.0.15 297 11/30/2022
3.0.14 300 11/23/2022
3.0.13 302 11/22/2022
3.0.12 301 11/21/2022
3.0.11 303 11/18/2022
3.0.10 305 11/18/2022
3.0.9 350 11/17/2022