Skip to content

build: adopt PublicApiSharp.Analyzers for public API tracking - #4428

Merged
glennawatson merged 3 commits into
mainfrom
chore/adopt-publicapisharp-analyzers
Aug 13, 2026
Merged

build: adopt PublicApiSharp.Analyzers for public API tracking#4428
glennawatson merged 3 commits into
mainfrom
chore/adopt-publicapisharp-analyzers

Conversation

@glennawatson

@glennawatson glennawatson commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

What kind of change does this PR introduce?

Build.

What is the new behavior?

Public API tracking moves to PublicApiSharp.Analyzers (PAS0001-PAS0005), matching Splat.

  • One PublicAPI.txt per project per target framework, holding nested C# that reads like source. Always current - no shipped/unshipped split and no promotion step, so an API change is reviewed as the diff itself.
  • Wired through EnablePublicApiBaseline; the package resolves the per-TFM baseline, so the AdditionalFiles glob is gone.
  • 232 baselines, covering every target framework including Apple.
  • The generated *_wpftmp projects are excluded from tracking: they sit in the real project's directory and resolve the same baseline path, so they overwrote it.

Two defects turned up while getting the build green, fixed here:

  • Samples, tests and benchmarks were still tracked. Each folder's Directory.Build.props sets TrackPublicApi to false, but it did so after importing the root props - which had already defaulted the value, derived EnablePublicApiBaseline from it and added the analyzer PackageReference. Both survived the later override, so ReactiveUI.Benchmarks, ReactiveUI.Samples.Maui and the ReactiveUI.Test.Utilities / ReactiveUI.TestGuiMocks helpers were all one baseline resolution away from failing on PAS0004. src/tests escaped only because it sets IsTestProject before the import. Moving the property group above the import fixes all three; the root already guards its default with Condition="'$(TrackPublicApi)' == ''".
  • The MAUI sample emitted 3762 uncoded warnings on Android. Unrelated to public API, but it blocked -warnaserror on the solution. See the commit for the mechanism; a stock dotnet new maui app reproduces it identically and the Android 37 band does not.

What is the current behavior?

Microsoft.CodeAnalysis.PublicApiAnalyzers with a PublicAPI.Shipped.txt / PublicAPI.Unshipped.txt pair per target framework, and tools/generate-publicapi.* to fold one into the other.

What might this PR break?

  • No product code changed and no public API changed; the baselines are a re-expression of the existing surface in the new format.
  • tools/generate-publicapi.sh / .ps1 are removed. To regenerate a baseline, empty it first, then run:
    dotnet format analyzers <proj> -f <tfm> --diagnostics PAS0001 PAS0003 --severity info
    The fix only adds and updates entries. A member that has since been removed is PAS0002, which has no code fix, so regenerating in place leaves a stale entry behind and fails the next build.

Checklist

  • I have read the Contribute guide
  • Tests have been added or updated (for bug fixes / features)
  • Docs have been added or updated (for bug fixes / features)
  • Changes target the main branch
  • PR title follows Conventional Commits

Additional information

Every baseline was regenerated from empty against current main, on .NET 11 preview 7 on both hosts:

  • 168 on Linux - the base, net4x, -windows and Android target frameworks.
  • 64 on a real Windows guest, which has the ios / tvos / macos / maccatalyst workloads Linux cannot install. Which target frameworks a project even offers is host-dependent, so each host is asked what it can build rather than told.

Verified two ways, both from clean:

  • dotnet build reactiveui.slnx -c Release -t:Rebuild -warnaserror on Linux: 0 warnings, 0 errors.
  • dotnet build reactiveui.slnx -c Release on real Windows: no errors. This is what actually checks the Apple, Windows and net4x baselines, since PAS0001/PAS0002/PAS0003 are errors by default.

glennawatson added a commit that referenced this pull request Aug 13, 2026
## What kind of change does this PR introduce?

Build.

## What is the new behavior?

`PublicApiSharp.Analyzers` moves to 1.0.7.

- 1.0.7 fixes the enum-member comparison, so a public enum whose
baseline is already correct no longer reports PAS0003.
- No baseline is regenerated. A full `dotnet build reactiveui.slnx -c
Release -t:Rebuild` produces no PAS diagnostics of any ID, so all 232
baselines still match byte-for-byte.

## What is the current behavior?

`PublicApiSharp.Analyzers` 1.0.5, as introduced by #4428. This PR
targets that branch, because `main` has no reference to the package at
all.

1.0.6 was tried first and is unusable here: it renders enum members with
their trailing separator but parses the baseline without it, so every
public enum member fails.

```
error PAS0003: 'Refresh = 4,' differs from the baseline;
  baseline declares 'Refresh = 4' but the API is 'Refresh = 4,'
```

That was 10 members across the three public enums in `ReactiveUI.Core`,
over 26 target frameworks - 130 errors - and no baseline could satisfy
it. `dotnet format analyzers` wrote zero changes (the fixer agreed the
file was already correct), and hand-editing the baseline to the
comma-less form the message asks for made it unparseable with `PAS0005:
Syntax error, ',' expected`.

## What might this PR break?

- None. No product code and no public API changed, and no baseline file
changed.

## Checklist
- [x] I have read the [Contribute
guide](https://www.reactiveui.net/contribute/index.html)
- [ ] Tests have been added or updated (for bug fixes / features)
- [ ] Docs have been added or updated (for bug fixes / features)
- [ ] Changes target the `main` branch
- [x] PR title follows [Conventional
Commits](https://www.conventionalcommits.org/)

## Additional information

Verified on Linux, so the Apple target framework baselines were not
exercised; everything Linux can compile, including the Windows target
frameworks via `EnableWindowsTargeting`, is green. The full solution
rebuild reports 0 errors. The only warnings come from
`examples/ReactiveUI.Samples.Maui` - un-IDed JNI registration notices
emitted by `Xamarin.Android.Common.targets` - and are unrelated to this
change.
@glennawatson
glennawatson force-pushed the chore/adopt-publicapisharp-analyzers branch from dfbf267 to 4c128b3 Compare August 13, 2026 03:28
- Track the public surface as one always-current PublicAPI.txt per project
  per target framework, holding nested C# that reads like source, so an API
  change is reviewed as the diff itself.
- Drop the shipped/unshipped pair and its promotion step, along with
  Microsoft.CodeAnalysis.PublicApiAnalyzers and tools/generate-publicapi.*.
- Resolve the baseline through EnablePublicApiBaseline; the package's targets
  add it per inner build, so the AdditionalFiles glob is no longer needed.
- Exclude the generated *_wpftmp projects, which sit in the real project's
  directory and would otherwise overwrite its baseline.
- Set TrackPublicApi before the root import in the examples, tests and
  benchmarks props. Setting it after left the derived EnablePublicApiBaseline
  and the analyzer reference switched on, so those projects were still tracked.
…AUI sample

The release link on the .NET 10 Android band (AndroidLinkMode=SdkOnly) strips
the connector, the n_ native callback and the delegate backing field out of
Mono.Android.dll before the marshal-method classifier looks for them. It finds
none of the registration pattern, so all 470 methods fall back to dynamic
registration - and say so, twice per method per ABI, as warnings the SDK logs
with no diagnostic code. No NoWarn can reach them and -warnaserror turns them
into a failed build.

- Turn marshal methods off for the android target framework, which states what
  the band already does rather than changing how the app registers anything.
- A stock `dotnet new maui` app reproduces it identically and the 37 band does
  not, so this is the toolchain rather than anything in this repository.
@glennawatson
glennawatson force-pushed the chore/adopt-publicapisharp-analyzers branch from 4c128b3 to 3cf8d5d Compare August 13, 2026 03:29
- MauiVersion to 11.0.0-preview.7.26406.9, matching the MAUI workload manifest.
- AspNetVersion, MicrosoftExtensionsVersion and SystemTextJsonVersion to
  11.0.0-preview.7.26381.103, matching the SDK.
- Microsoft.Maui.Controls.Compatibility stays put; it ships no preview 6 or 7
  and is already conditioned to net10.
@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.89%. Comparing base (efa283c) to head (86fcd69).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4428   +/-   ##
=======================================
  Coverage   93.89%   93.89%           
=======================================
  Files         359      359           
  Lines       15104    15104           
  Branches     1568     1568           
=======================================
  Hits        14182    14182           
  Misses        679      679           
  Partials      243      243           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@sonarqubecloud

Copy link
Copy Markdown

@glennawatson
glennawatson merged commit 749b862 into main Aug 13, 2026
13 checks passed
@glennawatson
glennawatson deleted the chore/adopt-publicapisharp-analyzers branch August 13, 2026 05:02
ChrisPulman pushed a commit that referenced this pull request Aug 17, 2026
…4435)

## What kind of change does this PR introduce?

Refactor. Deletes a duplicated file. No build configuration change.

## What is the new behavior?

**`ComponentModelFallbackConverter` has one definition instead of two
identical ones.**

- **It lives in `ReactiveUI.Shared/Bindings/Converter/`,** beside the
`ComponentModelConversion` helper both copies already delegated to.
- **Neither project file needed an entry for it.** `ReactiveUI` and
`ReactiveUI.Reactive` already compile `ReactiveUI.Shared/**/*.cs`
wholesale, so an existing glob picks it up. Both `.csproj` files are
byte-identical to `main`.
- **`[Preserve(AllMembers = true)]` is what allows one file to serve
every platform.** It is ReactiveUI's own attribute and is inert off
mobile, so the mobile linker still sees the converter and the desktop
targets are unaffected at runtime. That attribute was the only
meaningful difference between the two copies.

## What is the current behavior?

`Platforms/net/ComponentModelFallbackConverter.cs` and
`Platforms/mobile-common/ComponentModelFallbackConverter.cs` are
byte-equivalent apart from that `[Preserve]` attribute and an unused
`using System.Diagnostics;` on the desktop copy. The duplication scanner
reports the pair at 66.7 percent and 25 percent.

## What might this PR break?

**The declared public API of the desktop targets changes**, in one way:
the type now carries `[Preserve(AllMembers = true)]` where it previously
did not. Keeping the attribute is what lets a single file serve mobile,
so the desktop targets inherit it. `Preserve` is ReactiveUI's own
attribute and is inert away from the mobile linker, so nothing changes
at runtime - but it is part of the surface and the baselines now record
it.

- 22 baselines updated: `ReactiveUI` and `ReactiveUI.Reactive` across
net8/9/10/11, net462/472/481 and the four `-windows` targets.
- The Apple and Android baselines already recorded the attribute and are
unchanged.
- Otherwise the same type, in the same namespace, is emitted on every
target framework as before - only the file it is compiled from moved.

## Checklist
- [x] I have read the [Contribute
guide](https://www.reactiveui.net/contribute/index.html)
- [ ] Tests have been added or updated (for bug fixes / features)
- [ ] Docs have been added or updated (for bug fixes / features)
- [x] Changes target the `main` branch
- [x] PR title follows [Conventional
Commits](https://www.conventionalcommits.org/)

## Additional information

The diff is one file moving, one being deleted, and the `[Preserve]`
line appearing in the 22 baselines that did not already have it.

Verified with a clean `reactiveui.slnx` Release build on a real Windows
host: 0 errors, with `ReactiveUI` building 22 target frameworks and
`ReactiveUI.Reactive` 21 - ios, tvos, maccatalyst, macos, android,
Windows desktop, WinUI and .NET Framework included. Re-verified after
#4428 landed with `dotnet build reactiveui.slnx -c Release -t:Rebuild
-warnaserror` on Linux: 0 warnings, 0 errors.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants