Table of Contents

Getting Started

This guide takes a library from no API checks to a full chain: the analyzer marks intentional API, a test snapshots it, and an Atom target fails pull requests whose version bump does not match the change. Each step is useful on its own, so stop wherever you like.

Prerequisites

  • .NET 10 SDK
  • For the analyzer: any C# project (the analyzer targets netstandard2.0)
  • For the test utilities: a test project targeting net10.0, or any framework that consumes netstandard2.0
  • For the Atom module: an Atom build project targeting net10.0

1. Declare your public API

Install the analyzer in each library project, together with a [PublicAPI] attribute:

dotnet add package Invex.RepoUtils.PublicApiAnalyzers
dotnet add package JetBrains.Annotations

The analyzer now runs during every build and reports IPAA0001 for each public member that is not covered by a valid attribute:

using JetBrains.Annotations;

// Annotated: this type and its public members are intentionally part of the public API.
[PublicAPI]
public class MyService
{
    public string Name { get; set; } = "";

    public void Execute() { }
}

// IPAA0001: Public member 'InternalHelper' is missing [PublicAPI] or other valid attribute
public class InternalHelper { }

Either annotate InternalHelper or make it internal.

2. Snapshot the public surface

Add the test utilities and a snapshot library to your test project:

dotnet add package Invex.RepoUtils.TestUtils
dotnet add package Verify.NUnit

Then write one test per library assembly:

using Invex.RepoUtils.TestUtils;

[TestFixture]
public class PublicApiTests
{
    [Test]
    public Task VerifyPublicApiSurface() =>
        VerifyJson(PublicApiSurfaceTestUtil.GetPublicApiSurface(typeof(MyService).Assembly));
}

Run dotnet test, accept the new snapshot, and commit PublicApiTests.VerifyPublicApiSurface.verified.txt.

3. Check pull requests in CI

Add the Atom module to your build project:

dotnet add _atom/_atom.csproj package Invex.RepoUtils.Atom.Module

Mix ICheckPrForBreakingChanges into your build definition and point it at the snapshot files:

using Invex.RepoUtils.Atom.Module.Targets;

[BuildDefinition]
[GenerateEntryPoint]
internal interface IBuild : IWorkflowBuildDefinition, ICheckPrForBreakingChanges
{
    IEnumerable<RootedPath> ICheckPrForBreakingChanges.BreakingChangeFilesToCheck =>
        RootedFileSystem
            .Directory
            .GetFiles(RootedFileSystem.AtomRootDirectory / "tests", "*.verified.txt", SearchOption.AllDirectories)
            .Select(RootedFileSystem.CreateRootedPath);
}

Add the CheckPrForBreakingChanges target to your pull-request workflow (see the workflow example in Targets), then regenerate the workflow YAML with atom gen. The target compares the snapshots against your latest v{semver} release tag and posts a GitHub check run.

Next steps