Skip to content

Comments

RunApiDiff script and documentation improvements#10241

Merged
jeffhandley merged 57 commits intomainfrom
jeffhandley/apidiff-improvements
Feb 21, 2026
Merged

RunApiDiff script and documentation improvements#10241
jeffhandley merged 57 commits intomainfrom
jeffhandley/apidiff-improvements

Conversation

@jeffhandley
Copy link
Member

Running the API Diff for 11.0.0-preview.1 revealed some opportunities to make this script more user-friendly. The first hurdle faced was the search index for the staging NuGet feed for preview.1 did not have any results, and this led to needing to find all of the version parameter values through other means. Copilot CLI figured it all out, but it was difficult to achieve by hand, and its results weren't fully deterministic. Once the logic was understood, this led to a series of Copilot-authored improvements to the script and documentation with each step captured as its own commit.

A lot of the documentation and logic was based on running the diff after a release was published, but we began running it before the releases during .NET 10 and we intend to continue that approach going forward.

The SearchQueryService on some Azure DevOps feeds (especially per-build
shipping feeds) has an unpopulated search index that returns 0 results.
The flat2 (PackageBaseAddress) API works reliably on all feeds.

This changes DownloadPackage to try flat2 first, falling back to
SearchQueryService if flat2 doesn't find a match.
Make the -CoreRepo parameter optional. When omitted, the script resolves
the git repository root relative to its own location using
'git rev-parse --show-toplevel'. If the root cannot be determined, it
fails with a descriptive error.
Paths containing ~ or relative segments fail when passed to the api diff
tool. Resolve both paths to their full absolute form before use.
The previous/before version is typically a GA release available on
nuget.org. Default to the public NuGet feed instead of the dotnet10
Azure DevOps feed.
…nal for GA

Rename PreviousPreviewOrRC/CurrentPreviewOrRC to PreviousReleaseKind/
CurrentReleaseKind for clarity.

Make PreviousPreviewNumberVersion and CurrentPreviewNumberVersion
optional, defaulting to '0' when the release kind is 'ga'. For non-GA
release kinds, a validation error is raised if the version number is
not provided.
…wRCNumber

Rename PreviousDotNetVersion/CurrentDotNetVersion to PreviousMajorMinor/
CurrentMajorMinor and PreviousPreviewNumberVersion/
CurrentPreviewNumberVersion to PreviousPreviewRCNumber/
CurrentPreviewRCNumber for clarity.
When TmpFolder is not specified, create a unique temporary directory
using GetTempPath and GetRandomFileName.
When CurrentMajorMinor, CurrentReleaseKind, or CurrentPreviewRCNumber
are not specified, query the CurrentNuGetFeed for the latest
Microsoft.NETCore.App.Ref package version and parse the version
components from it (e.g. 11.0.0-preview.1.26104.118 -> 11.0, preview, 1).
Extract version discovery into a reusable DiscoverVersionFromFeed
function and apply it to both Previous and Current parameters. When
PreviousMajorMinor or PreviousReleaseKind are not specified, they are
discovered from the PreviousNuGetFeed (default: nuget.org, which will
resolve to the latest GA version).
Allow the simplest invocation:
  .\RunApiDiff.ps1 <current-nuget-feed-url>
Document all parameters, their defaults, and auto-discovery behavior.
Add quick start, prerequisites, and multiple usage examples.
Note the transport feed should match the version being compared, and
mention the -InstallApiDiff flag as an alternative.
Both feeds now default to nuget.org. The same-version validation
added previously will catch the case where both resolve to the same
version and prompt the user to specify different feeds or explicit
version parameters.
Replace the separate -PreviousReleaseKind/-PreviousPreviewRCNumber and
-CurrentReleaseKind/-CurrentPreviewRCNumber parameters with single
-PreviousPrereleaseLabel and -CurrentPrereleaseLabel parameters that
accept values like 'preview.7' or 'rc.1'. Omit for GA releases.

The labels are parsed internally into ReleaseKind and PreviewRCNumber
for use by the existing helper functions.
…el from it

Rename -PreviousPackageVersion/-CurrentPackageVersion to
-PreviousVersion/-CurrentVersion. When a Version is provided, the
MajorMinor and PrereleaseLabel values are automatically parsed from
it, eliminating the need to specify them separately.

Add ValidatePattern to PrereleaseLabel parameters to enforce the
'preview.N' or 'rc.N' format.

Update examples to show the simplified usage with only -PreviousVersion
and -CurrentVersion.
Move ParseVersionString to the Functions section and reuse it inside
DiscoverVersionFromFeed instead of duplicating the regex parsing.
All helper functions are now defined together in the Functions section
rather than being scattered in the execution section.
This function was never called and referenced a nonexistent variable
(\). It was leftover from when the apidiff tool was built from
source rather than installed as a dotnet tool.
Replace Invoke-Expression string-building with direct & invocation and
argument splatting for the apidiff tool call. This avoids the fragile
Invoke-Expression pattern and properly handles paths with spaces.
Add previousMajorMinor, previousReleaseKind, previousPreviewRCNumber,
currentMajorMinor, currentReleaseKind, and currentPreviewRCNumber as
explicit parameters instead of referencing script-scoped variables.
Switch callers to use named parameters for clarity. Mark required
parameters as Mandatory.
Remove the misleading 'Generate strings with no whitespace' comment
that no longer described what followed, and remove a double blank line.
The GA patch branch was producing folder names like '7.01' instead of
'7.0.1' due to a missing dot separator between dotNetVersion and
previewNumberVersion.
Change ExcludeNetCore, ExcludeAspNetCore, ExcludeWindowsDesktop, and
InstallApiDiff from [bool] to [switch]. This follows PowerShell idiom,
allowing -ExcludeNetCore instead of -ExcludeNetCore \$true.
Make releaseKind and previewNumberVersion optional in DownloadPackage
since they are unused when an exact version is provided. Add validation
that either version or both search params are specified. Switch all
DownloadPackage calls to use named parameters for clarity.
Write-Output sends to stdout which can interfere with function return
values. Write-Host sends to the display stream only, which is correct
for informational/colored messages.
The pattern was unanchored and too permissive, matching partial strings
like '7.0abc'. Now uses ^(\d+\.\d+)?$ to match either empty or a
properly formatted major.minor version.
The validation above already ensures both releaseKind and
previewNumberVersion are non-empty, so the ElseIf guard was
always true. Replace with a simple Else.
Introduce a project-scoped Copilot skill (.github/skills/api-diff/) that
guides API diff generation using release-notes/RunApiDiff.ps1.

SKILL.md provides a concise workflow overview with links to reference
files for each stage:

- reference/interpreting-input.md: version format mapping rules,
  clarification prompts for ambiguous input, and usage examples
- reference/parameters.md: full script parameter reference (version,
  feed, and switch parameters)
- reference/progress-monitoring.md: disk-based progress monitoring
  to report newly generated diff files during script execution
@jeffhandley jeffhandley requested a review from ericstj February 10, 2026 13:48
jeffhandley and others added 7 commits February 13, 2026 09:20
Co-authored-by: Eric StJohn <ericstj@microsoft.com>
Reduce the skill's responsibility to a single job: interpret the user's
prompt, map it to RunApiDiff.ps1 parameters, and run the script. Remove
interactive clarification flows, progress monitoring via disk polling,
and duplicated parameter logic that was redundant with RunApiDiff.md/ps1.

Add note about ANSI progress bar output making completion detection
difficult, instructing agents to check process exit status instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Change PreviousNuGetFeed default from nuget.org to the dnceng public
transport feed constructed from PreviousMajorMinor, matching the
existing CurrentNuGetFeed behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
DiscoverVersionFromFeed now accepts an sdkName parameter instead of
hardcoding microsoft.netcore.app.ref, enabling version queries for
AspNetCore and WindowsDesktop framework packs independently.

ProcessSdk no longer passes exact NETCore versions to non-NETCore SDK
downloads, allowing each framework to resolve its own version from
the feed. This handles pre-.NET 10 releases where framework versions
could differ.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace GetNextVersion (which hardcoded preview.7 → rc.1, rc.2 → ga)
with GetNextVersionFromFeed that queries the NuGet feed to find the
actual next milestone. This handles any number of previews or RCs
without assumptions about the release cadence.

When no newer version exists on the same major, the function probes
the next major version's feed automatically.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove reference/interpreting-input.md and reference/parameters.md,
consolidating the skill into a single file. The skill now only adds
natural language to parameter mapping and defers to RunApiDiff.md for
the full parameter reference.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Contributor

Copilot AI commented Feb 19, 2026

@jeffhandley I've opened a new pull request, #10280, to work on those changes. Once the pull request is ready, I'll request review from you.

jeffhandley and others added 3 commits February 18, 2026 22:26
* Initial plan

* Refactor feed URL template into GetDncEngFeedUrl function

Co-authored-by: jeffhandley <1031940+jeffhandley@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jeffhandley <1031940+jeffhandley@users.noreply.github.com>
@jeffhandley jeffhandley requested a review from ericstj February 19, 2026 06:47
Copy link
Member

@ericstj ericstj left a comment

Choose a reason for hiding this comment

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

Minor suggestion on feeds.

I like all the reduction of parameters by inferring and searching. It makes this much easier to use.

I wish the nuget searching/downloading didn't require so much code here. We could use https://learn.microsoft.com/en-us/nuget/reference/powershell-reference but I don't want to feature-creep this PR.

jeffhandley and others added 3 commits February 20, 2026 18:34
Replace version-specific dnceng feeds (dotnet{N}) with the single
dotnet-public feed that contains all released and nightly packages.
Remove GetDncEngFeedUrl function and nuget.org fallback. The feed URL
is defined once as $DotNetPublicFeedUrl. The -InstallApiDiff switch
now installs from $CurrentNuGetFeed (defaults to dotnet-public),
removing the transport feed dependency.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Updated RunApiDiff.ps1 to construct the transport feed URL from the
current major version (dotnet{MAJOR}-transport) instead of using the
CurrentNuGetFeed parameter. Updated RunApiDiff.md documentation to
reflect the new feed source and install command.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- MD040: Add language specifier to fenced code block in RunApiDiff.md
- PSAvoidUsingWriteHost: Add SuppressMessage attribute to Write-Color
- PSAvoidUsingEmptyCatchBlock: Add no-op statement to empty catch block
- PSAvoidUsingInvokeExpression: Replace Invoke-Expression with & operator
- PSAvoidUsingPositionalParameters: Use named parameters in all calls
- PSUseBOMForUnicodeEncodedFile: Add UTF-8 BOM to RunApiDiff.ps1

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jeffhandley jeffhandley merged commit d83dc0a into main Feb 21, 2026
8 checks passed
@jeffhandley jeffhandley deleted the jeffhandley/apidiff-improvements branch February 21, 2026 06:05
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.

3 participants