Skip to content

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Oct 15, 2025

Plan: Create Obsolete APIs Inventory Tool

  • Create new console tool project at eng/tools/ObsoleteInventory/
    • Create project structure with .csproj file
    • Add Program.cs with main entry point
    • Add ObsoleteApiRecord model
    • Add logic to scan C# files
    • Add Roslyn parsing to detect obsolete attributes
    • Add git blame integration to find introduction dates
    • Add Markdown report generation
    • Add README.md with usage instructions
  • Test the tool on the repository
  • Generate the initial ObsoletedApis.md report at repository root
  • Verify the generated report is accurate

Summary

Created a fully functional tool that:

  • Scans all C# source files under src/ (excluding tests, samples, benchmarks, generated code)
  • Identifies APIs marked with [Obsolete] or [ObsoleteAttribute]
  • Uses git blame to determine when each obsolete marking was first introduced
  • Generates a comprehensive Markdown report at the repository root
  • Supports --verify mode for CI validation

The tool successfully identified 182 obsolete APIs in the repository and generated a detailed report with all required fields:

  • API signature (fully qualified)
  • Kind (Type, Method, Property, etc.)
  • Introduction date (from git blame)
  • Commit hash (linked to GitHub)
  • IsError flag
  • Obsolete message
  • File path

The report is sorted by introduction date (oldest first) as required.

Original prompt

Objective
Create an automated, reproducible inventory of all APIs currently marked with the Obsolete attribute in the main branch and add a generated Markdown report (ObsoletedApis.md) at the repository root. The report must list each obsolete API and the date the obsolete marking was first introduced into main (earliest commit that added the [Obsolete] attribute for that declaration), sorted from oldest to newest.

Scope
Include all C# source files under src/ (exclude tests, benchmarks, samples, eng/, tools/, obj/, bin/, generated code, and anything containing the auto-generated header). Detect any attribute forms: [Obsolete], [Obsolete("message")], [Obsolete("message", true)], and [ObsoleteAttribute(...)] (case-insensitive). Do not include members that have since had the Obsolete attribute removed (only what is currently obsolete on main). Each individual member or type with its own Obsolete attribute should appear as its own row. If both a type and a member inside it are marked obsolete independently, both appear.

Data Fields (Markdown table columns)
| API | Kind | IntroducedObsoleteDate | Commit | IsError | Message | File |

  • API: Fully qualified signature (namespace + containing types + member signature). Use Roslyn symbol display (CSharpErrorMessageFormat or a custom format that includes generic arity, parameters, and return type where applicable). Enclose in backticks.
  • Kind: Type, Method, Property, Field, Event, EnumMember, Constructor, Operator, etc.
  • IntroducedObsoleteDate: ISO 8601 committer date of the first commit that introduced the Obsolete attribute for this declaration.
  • Commit: Short hash hyperlinked to the commit on GitHub.
  • IsError: true if ObsoleteAttribute second ctor parameter (bool) is true; otherwise false.
  • Message: The Obsolete message string (escape pipe characters to avoid table break; truncate at 240 chars with an ellipsis if longer, but retain full internally for potential future use).
  • File: Repository-relative path to the source file.

Ordering: Sort the table ascending by IntroducedObsoleteDate (oldest first). Provide a final Total count below the table.

Implementation Requirements

  1. Add a new console tool project under eng/tools/ObsoleteInventory (net8.0 or net9.0 if repo already uses it) that:
    • Walks src/ recursively (Directory.EnumerateFiles with *.cs) filtering out unwanted paths (tests, samples, benchmarks, obj, bin, generated).
    • Uses Roslyn (Microsoft.CodeAnalysis.CSharp) to parse syntax trees and gather all declarations with an Obsolete attribute.
    • For each obsolete declaration, determine the source line number where the Obsolete attribute appears (use first attribute syntax location containing "Obsolete").
    • Runs a single git blame per file (git blame --line-porcelain) and caches mapping line->(commit,date).
    • Determines the introduction commit as the blame commit for the line containing the Obsolete attribute token. (Optional improvement: If needed, refine by running git log -L but initial implementation can use blame.)
    • Retrieves commit date (if not in blame output) with git show -s --format=%cI (cache commit->date).
    • Builds in-memory records and sorts by date.
    • Generates ObsoletedApis.md content exactly as specified (root-relative path ../ObsoletedApis.md when writing from tool directory).
    • Escapes pipe characters in Message with |.
    • Ensures deterministic ordering and stable formatting.
  2. Add a top-level script or a Target in eng/targets if repo convention prefers (optional).
  3. Add the generated ObsoletedApis.md at repository root in this PR (the tool should run locally to produce it). If generation time is long, acceptable to run during PR creation and commit the produced file.
  4. Include README snippet in the tool folder explaining usage: dotnet run -c Release -- (optionally --verify to fail if file differs) so CI can later enforce freshness.
  5. Add a minimal CI step (if lightweight and consistent with repo patterns) or leave instructions only (OK to skip CI wiring if out-of-scope for this initial PR; just document potential future enforcement).
  6. The tool must ignore declarations inside #if false or excluded by conditional compilation? (Out-of-scope; accept current parse; no preprocessor evaluation required). Do not evaluate conditional symbols; just treat syntactically present code.
  7. Exclude any file whose first 5 non-empty lines contain or AutoGenerated.

Acceptance Criteria

  • New tool project builds with existing solution (add to appropriate solution file if solutions are curated; follow repo norms).
  • ObsoletedApis.md exists at root with populated table and at least one entry.
  • Table is sorted oldest to newest by IntroducedObsoleteDate.
  • Each Commit cell links correctly (https://github.com/dotnet/aspnetcore/commit/).
  • Formatting passes markdown lint (no ...

This pull request was created as a result of the following prompt from Copilot chat.

Objective
Create an automated, reproducible inventory of all APIs currently marked with the Obsolete attribute in the main branch and add a generated Markdown report (ObsoletedApis.md) at the repository root. The report must list each obsolete API and the date the obsolete marking was first introduced into main (earliest commit that added the [Obsolete] attribute for that declaration), sorted from oldest to newest.

Scope
Include all C# source files under src/ (exclude tests, benchmarks, samples, eng/, tools/, obj/, bin/, generated code, and anything containing the auto-generated header). Detect any attribute forms: [Obsolete], [Obsolete("message")], [Obsolete("message", true)], and [ObsoleteAttribute(...)] (case-insensitive). Do not include members that have since had the Obsolete attribute removed (only what is currently obsolete on main). Each individual member or type with its own Obsolete attribute should appear as its own row. If both a type and a member inside it are marked obsolete independently, both appear.

Data Fields (Markdown table columns)
| API | Kind | IntroducedObsoleteDate | Commit | IsError | Message | File |

  • API: Fully qualified signature (namespace + containing types + member signature). Use Roslyn symbol display (CSharpErrorMessageFormat or a custom format that includes generic arity, parameters, and return type where applicable). Enclose in backticks.
  • Kind: Type, Method, Property, Field, Event, EnumMember, Constructor, Operator, etc.
  • IntroducedObsoleteDate: ISO 8601 committer date of the first commit that introduced the Obsolete attribute for this declaration.
  • Commit: Short hash hyperlinked to the commit on GitHub.
  • IsError: true if ObsoleteAttribute second ctor parameter (bool) is true; otherwise false.
  • Message: The Obsolete message string (escape pipe characters to avoid table break; truncate at 240 chars with an ellipsis if longer, but retain full internally for potential future use).
  • File: Repository-relative path to the source file.

Ordering: Sort the table ascending by IntroducedObsoleteDate (oldest first). Provide a final Total count below the table.

Implementation Requirements

  1. Add a new console tool project under eng/tools/ObsoleteInventory (net8.0 or net9.0 if repo already uses it) that:
    • Walks src/ recursively (Directory.EnumerateFiles with *.cs) filtering out unwanted paths (tests, samples, benchmarks, obj, bin, generated).
    • Uses Roslyn (Microsoft.CodeAnalysis.CSharp) to parse syntax trees and gather all declarations with an Obsolete attribute.
    • For each obsolete declaration, determine the source line number where the Obsolete attribute appears (use first attribute syntax location containing "Obsolete").
    • Runs a single git blame per file (git blame --line-porcelain) and caches mapping line->(commit,date).
    • Determines the introduction commit as the blame commit for the line containing the Obsolete attribute token. (Optional improvement: If needed, refine by running git log -L but initial implementation can use blame.)
    • Retrieves commit date (if not in blame output) with git show -s --format=%cI (cache commit->date).
    • Builds in-memory records and sorts by date.
    • Generates ObsoletedApis.md content exactly as specified (root-relative path ../ObsoletedApis.md when writing from tool directory).
    • Escapes pipe characters in Message with |.
    • Ensures deterministic ordering and stable formatting.
  2. Add a top-level script or a Target in eng/targets if repo convention prefers (optional).
  3. Add the generated ObsoletedApis.md at repository root in this PR (the tool should run locally to produce it). If generation time is long, acceptable to run during PR creation and commit the produced file.
  4. Include README snippet in the tool folder explaining usage: dotnet run -c Release -- (optionally --verify to fail if file differs) so CI can later enforce freshness.
  5. Add a minimal CI step (if lightweight and consistent with repo patterns) or leave instructions only (OK to skip CI wiring if out-of-scope for this initial PR; just document potential future enforcement).
  6. The tool must ignore declarations inside #if false or excluded by conditional compilation? (Out-of-scope; accept current parse; no preprocessor evaluation required). Do not evaluate conditional symbols; just treat syntactically present code.
  7. Exclude any file whose first 5 non-empty lines contain or AutoGenerated.

Acceptance Criteria

  • New tool project builds with existing solution (add to appropriate solution file if solutions are curated; follow repo norms).
  • ObsoletedApis.md exists at root with populated table and at least one entry.
  • Table is sorted oldest to newest by IntroducedObsoleteDate.
  • Each Commit cell links correctly (https://github.com/dotnet/aspnetcore/commit/).
  • Formatting passes markdown lint (no trailing double spaces except required for line breaks, header separated by blank line from preceding text if necessary).
  • Running the tool twice without code changes yields no diff.

Out-of-scope (document in tool README)

  • Distinguishing public vs internal API.
  • Detecting if obsolete status predates .NET 8 vs later (can be added later).
  • Advanced original-introduction detection across renames/moves (initial blame approach acceptable).

Deliverables in PR

  • eng/tools/ObsoleteInventory/* (project + source)
  • ObsoletedApis.md (generated)
  • Optional README in tool directory.
  • Any solution file updates if required.

Please implement the tool and generate the initial report.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

- Created console tool at eng/tools/ObsoleteInventory
- Tool scans all C# files in src/ for [Obsolete] attributes
- Uses Roslyn for syntax parsing
- Uses git blame to determine when obsolete marking was introduced
- Generates ObsoletedApis.md with 182 obsolete APIs
- Supports --verify mode for CI validation
- Added README with usage instructions

Co-authored-by: ilonatommy <32700855+ilonatommy@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants