Skip to content

Address follow-up review feedback for matcher reuse and null-pattern validation#1770

Open
jpinz wants to merge 14 commits intomainfrom
fix/glob-pattern-matching
Open

Address follow-up review feedback for matcher reuse and null-pattern validation#1770
jpinz wants to merge 14 commits intomainfrom
fix/glob-pattern-matching

Conversation

@jpinz
Copy link
Copy Markdown
Member

@jpinz jpinz commented Apr 7, 2026

This pull request refactors and modernizes the file pattern matching logic throughout the codebase. The main improvements are the introduction of a new PatternMatchingUtility.CompiledMatcher class for efficient, reusable pattern matching, the removal of legacy pattern matching code, and the simplification of APIs that deal with file pattern matching. These changes improve maintainability, performance, and code clarity.

Worth noting is that as a part of this change, the ordering of the SearchPatterns in each detector is now ordered so that earlier patterns have a higher priority when multiple patterns match a file.

Additionally, only one ProcessRequest is returned per matching file, previously we returned one per matching pattern.

Old behavior (one per matching pattern): If a file like package.json matched both *.json and package.json, the detector's OnFileFoundAsync would be called twice for the same file. Both calls would parse the same content and register the same components into the same SingleFileComponentRecorder (since it's keyed by file path via CreateSingleFileComponentRecorder(lazyComponentStream.Location)). The second call is pure waste.

New behavior (one per file): Each file is processed exactly once. No duplicate parsing, no redundant RegisterUsage calls.

…ob patterns efficiently. And align on one implementation of pattern/file matching.
@jpinz jpinz requested a review from JamieMagee April 7, 2026 21:13
@jpinz jpinz self-assigned this Apr 7, 2026
Copilot AI review requested due to automatic review settings April 7, 2026 21:13
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR migrates file name pattern matching to a centralized implementation (PatternMatchingUtility), removing legacy matching logic from PathUtilityService and updating the directory/file enumeration code paths and tests to use the new matcher.

Changes:

  • Introduced span-based pattern matching using System.IO.Enumeration.FileSystemName.MatchesSimpleExpression and a reusable CompiledMatcher.
  • Removed MatchesPattern from IPathUtilityService / PathUtilityService and updated callers to use PatternMatchingUtility.
  • Expanded/updated unit tests to cover the new matching behavior and APIs.
Show a summary per file
File Description
test/Microsoft.ComponentDetection.TestsUtilities/DetectorTestUtilityBuilder.cs Updates test utility pattern selection to use PatternMatchingUtility.GetMatchingPattern.
test/Microsoft.ComponentDetection.Common.Tests/SafeFileEnumerableTests.cs Removes mocking for the deleted IPathUtilityService.MatchesPattern API.
test/Microsoft.ComponentDetection.Common.Tests/PatternMatchingUtilityTests.cs Updates tests to the new Compile/CompiledMatcher APIs and adds more matching cases.
src/Microsoft.ComponentDetection.Contracts/IPathUtilityService.cs Removes MatchesPattern from the path utility contract.
src/Microsoft.ComponentDetection.Common/SafeFileEnumerable.cs Switches file inclusion + matched-pattern selection to a compiled matcher.
src/Microsoft.ComponentDetection.Common/PatternMatchingUtility.cs Replaces custom wildcard logic with FileSystemName.MatchesSimpleExpression; adds CompiledMatcher.
src/Microsoft.ComponentDetection.Common/PathUtilityService.cs Removes legacy pattern matching implementations.
src/Microsoft.ComponentDetection.Common/FastDirectoryWalkerFactory.cs Uses CompiledMatcher for file filtering and matched-pattern resolution; removes MatchesAnyPattern.

Copilot's findings

Comments suppressed due to low confidence (2)

src/Microsoft.ComponentDetection.Common/FastDirectoryWalkerFactory.cs:214

  • patterns is enumerated multiple times here (string.Join and then PatternMatchingUtility.Compile(patterns)), which can be problematic for lazy/non-repeatable IEnumerable<string> inputs and adds overhead. Consider converting to an array once (e.g., var patternArray = patterns.ToArray()) and using it for both logging and compilation.
            this.logger.LogDebug("Logging patterns {Patterns} for {Root}", string.Join(":", patterns), root.FullName);

            var compiled = PatternMatchingUtility.Compile(patterns);

src/Microsoft.ComponentDetection.Common/FastDirectoryWalkerFactory.cs:236

  • This method compiles patterns and also calls Subscribe(root, patterns), which currently re-enumerates and recompiles patterns again. Materializing patterns once (array) and reusing a single compiled matcher for both filtering and MatchedPattern selection would avoid redundant work and prevents issues if patterns is a single-pass/lazy enumerable.
    public IObservable<ProcessRequest> GetFilteredComponentStreamObservable(DirectoryInfo root, IEnumerable<string> patterns, IComponentRecorder componentRecorder)
    {
        var compiled = PatternMatchingUtility.Compile(patterns);

        var observable = this.Subscribe(root, patterns).OfType<FileInfo>()
            .Select(f => new
  • Files reviewed: 8/8 changed files
  • Comments generated: 1

@jpinz jpinz requested a review from Copilot April 8, 2026 17:45
@jpinz jpinz marked this pull request as ready for review April 8, 2026 17:45
@jpinz jpinz requested a review from a team as a code owner April 8, 2026 17:45
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 8, 2026

👋 Hi! It looks like you modified some files in the Detectors folder.
You may need to bump the detector versions if any of the following scenarios apply:

  • The detector detects more or fewer components than before
  • The detector generates different parent/child graph relationships than before
  • The detector generates different devDependencies values than before

If none of the above scenarios apply, feel free to ignore this comment 🙂

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR centralizes file-pattern matching by replacing custom PathUtilityService logic with a standardized PatternMatchingUtility implementation backed by System.IO.Enumeration.FileSystemName, and updates directory enumeration code paths and tests accordingly.

Changes:

  • Introduces PatternMatchingUtility.CompiledMatcher and updates consumers to use compiled span-based pattern matching.
  • Removes MatchesPattern from IPathUtilityService/PathUtilityService and updates call sites.
  • Expands/updates pattern matching tests to cover more patterns and case-insensitive matching.
Show a summary per file
File Description
test/Microsoft.ComponentDetection.TestsUtilities/DetectorTestUtilityBuilder.cs Switches test helper pattern selection to PatternMatchingUtility.GetMatchingPattern.
test/Microsoft.ComponentDetection.Common.Tests/SafeFileEnumerableTests.cs Removes mocks for the deleted IPathUtilityService.MatchesPattern API.
test/Microsoft.ComponentDetection.Common.Tests/PatternMatchingUtilityTests.cs Updates tests to use compiled matcher + adds coverage for case-insensitivity and pattern selection.
src/Microsoft.ComponentDetection.Contracts/IPathUtilityService.cs Removes MatchesPattern from the contract.
src/Microsoft.ComponentDetection.Common/SafeFileEnumerable.cs Uses a precompiled matcher for filtering and for retrieving the matched pattern.
src/Microsoft.ComponentDetection.Common/PatternMatchingUtility.cs Replaces manual matching with FileSystemName.MatchesSimpleExpression and adds CompiledMatcher.
src/Microsoft.ComponentDetection.Common/PathUtilityService.cs Deletes legacy pattern matching implementations.
src/Microsoft.ComponentDetection.Common/FastDirectoryWalkerFactory.cs Converts file scanning/filtering to use compiled matcher (including matched-pattern selection).

Copilot's findings

  • Files reviewed: 8/8 changed files
  • Comments generated: 3

@jpinz
Copy link
Copy Markdown
Member Author

jpinz commented Apr 8, 2026

@copilot apply changes based on the comments in this thread

Copilot AI review requested due to automatic review settings April 8, 2026 18:12
@jpinz jpinz review requested due to automatic review settings April 8, 2026 18:12
Copilot AI review requested due to automatic review settings April 8, 2026 18:12
@jpinz jpinz review requested due to automatic review settings April 8, 2026 18:12
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 8, 2026

@copilot apply changes based on the comments in this thread

Implemented the requested updates from that review thread in commit bd19239: centralized duplicate matching logic in PatternMatchingUtility, documented first-match pattern precedence, and updated API visibility for Compile/CompiledMatcher to align with test/public usage. Full tests are passing after the change.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • 4myvsblobprodcus32.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/86123D718A0A7D5E3D8DDB87D50A845A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • 5dkvsblobprodcus355.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/86123D718A0A7D5E3D8DDB87D50A845A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • 5rqvsblobprodcus385.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/2D3586D8C912F6D195254B43F0F0042B/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/EAC58970BF56570ECF9A3336E1CC2C51/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/D93C69A3F90DACDB68555AD6306FA9CB/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • azuresdkartifacts.blob.core.windows.net
    • Triggering command: /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/csharp/tools/linux64/Semmle.Autobuild.CSharp /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/csharp/tools/linux64/Semmle.Autobuild.CSharp (dns block)
  • c78vsblobprodcus322.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/2D3586D8C912F6D195254B43F0F0042B/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/4EB20032E82B2584A5C53CFFE5CD470A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/86123D718A0A7D5E3D8DDB87D50A845A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • e7bvsblobprodcus348.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/6159872093532F2B0C5E6E8E99896FA2/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • jd4vsblobprodcus366.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/CDD3F901B58BCEF02488C08DF1C7A1CC/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force dotn�� by/2e77cb38a0e6dc3803102e0eb5adf090f6f56bd927c0d1e8a0f3c9dccba384d0/config.json (dns block)
  • k4kvsblobprodcus344.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/2D3586D8C912F6D195254B43F0F0042B/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/EAC58970BF56570ECF9A3336E1CC2C51/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/D93C69A3F90DACDB68555AD6306FA9CB/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • m16vsblobprodcus374.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/EFA774C66662112D9EC4DF5EF75C0019/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • pdfvsblobprodcus380.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/2D3586D8C912F6D195254B43F0F0042B/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/86123D718A0A7D5E3D8DDB87D50A845A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/C8FA87C461E8D947D5E484A1822A0126/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title Migrate to efficient glob pattern matching implementation Address review feedback on pattern matcher API, logic deduplication, and precedence docs Apr 8, 2026
Copilot finished work on behalf of jpinz April 8, 2026 18:13
@jpinz jpinz requested a review from Copilot April 8, 2026 18:25
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the centralized pattern-matching API in Microsoft.ComponentDetection.Common to align visibility with intended usage, deduplicate matching behavior across entry points, and document/enforce first-match-wins precedence when multiple patterns match the same filename.

Changes:

  • Made PatternMatchingUtility.Compile(...) / CompiledMatcher public and consolidated MatchesPattern, GetMatchingPattern, and compiled matching to a single shared implementation.
  • Updated file enumeration and directory walking to use the compiled matcher and to apply explicit first-match-wins pattern precedence.
  • Updated test utilities and unit tests to use the new API and removed usage of IPathUtilityService.MatchesPattern (including removing it from the interface).
Show a summary per file
File Description
test/Microsoft.ComponentDetection.TestsUtilities/DetectorTestUtilityBuilder.cs Uses PatternMatchingUtility.GetMatchingPattern instead of instantiating PathUtilityService for test pattern selection.
test/Microsoft.ComponentDetection.Common.Tests/SafeFileEnumerableTests.cs Removes mocks for IPathUtilityService.MatchesPattern since enumeration no longer depends on it.
test/Microsoft.ComponentDetection.Common.Tests/PatternMatchingUtilityTests.cs Expands/updates coverage for compile/match APIs, case-insensitivity, and precedence behavior.
src/Microsoft.ComponentDetection.Contracts/IPathUtilityService.cs Removes MatchesPattern from the public Contracts interface.
src/Microsoft.ComponentDetection.Common/SafeFileEnumerable.cs Switches enumeration matching + selected-pattern reporting to CompiledMatcher, documenting first-match-wins behavior.
src/Microsoft.ComponentDetection.Common/PatternMatchingUtility.cs Introduces public Compile, MatchesPattern, GetMatchingPattern, and shared internal matching helpers.
src/Microsoft.ComponentDetection.Common/PathUtilityService.cs Removes MatchesPattern implementations now replaced by PatternMatchingUtility.
src/Microsoft.ComponentDetection.Common/FastDirectoryWalkerFactory.cs Replaces prior per-pattern matching logic with a compiled matcher and dedupes per-file matching in filtered observables.

Copilot's findings

  • Files reviewed: 8/8 changed files
  • Comments generated: 3

Comment on lines +14 to +20
private readonly IPathUtilityService pathUtilityService;
private readonly bool recursivelyScanDirectories;
private readonly Func<FileInfo, bool> fileMatchingPredicate;
private readonly PatternMatchingUtility.CompiledMatcher compiledMatcher;
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

searchPatterns is now assigned but never used after switching to compiledMatcher. With TreatWarningsAsErrors enabled, this will raise CS0414 and fail the build. Remove the searchPatterns field/assignment (or use it for logging/debugging) so the file compiles cleanly.

Copilot uses AI. Check for mistakes.
Comment on lines 8 to 23
public static class PatternMatchingUtility
{
public delegate bool FilePatternMatcher(ReadOnlySpan<char> span);
public static bool MatchesPattern(string pattern, string fileName) => IsPatternMatch(pattern, fileName.AsSpan());

public static FilePatternMatcher GetFilePatternMatcher(IEnumerable<string> patterns)
/// <summary>
/// Returns the first matching pattern for <paramref name="fileName"/>.
/// Earlier patterns in <paramref name="patterns"/> have higher priority when multiple match.
/// </summary>
/// <returns>The first matching pattern, or <see langword="null"/> if no patterns match.</returns>
public static string? GetMatchingPattern(string fileName, IEnumerable<string> patterns)
=> GetFirstMatchingPattern(fileName.AsSpan(), patterns);

public static CompiledMatcher Compile(IEnumerable<string> patterns) => new(patterns);

private static string? GetFirstMatchingPattern(ReadOnlySpan<char> fileName, IEnumerable<string> patterns)
{
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

Now that Compile(...) / CompiledMatcher are public, passing null for patterns will currently throw a NullReferenceException (via patterns.ToArray() / foreach). Add explicit ArgumentNullException.ThrowIfNull(patterns) (and consider similar validation for pattern/fileName) to make failures deterministic and user-friendly.

Copilot uses AI. Check for mistakes.
Comment on lines 23 to 29
/// <summary>
/// Returns true when the below file path exists under the above file path.
/// </summary>
/// <param name="aboveFilePath">The top file path.</param>
/// <param name="belowFilePath">The file path to find within the top file path.</param>
/// <returns>Returns true if the below file path exists under the above file path, otherwise false.</returns>
bool IsFileBelowAnother(string aboveFilePath, string belowFilePath);
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

Removing MatchesPattern from the public IPathUtilityService interface is a breaking change for any external implementers/consumers of the Contracts package. If compatibility is required, consider keeping it (e.g., [Obsolete] and forwarding to PatternMatchingUtility.MatchesPattern) or introducing a new interface rather than deleting the member.

Copilot uses AI. Check for mistakes.
@jpinz
Copy link
Copy Markdown
Member Author

jpinz commented Apr 8, 2026

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR follows up on the centralized pattern-matching migration by hardening public pattern-matching APIs against null inputs, restoring contract compatibility for IPathUtilityService.MatchesPattern(...) via an obsolete shim, and cleaning up pattern-matching call sites to use the new compiled matcher approach.

Changes:

  • Added null-argument guards and a compiled matcher API to PatternMatchingUtility, plus expanded unit test coverage for new behaviors.
  • Reintroduced IPathUtilityService.MatchesPattern(string, string) as an [Obsolete] compatibility shim and updated PathUtilityService to forward to PatternMatchingUtility.
  • Updated filesystem enumeration code paths (SafeFileEnumerable / FastDirectoryWalkerFactory / test utilities) to use compiled matching and removed now-unused pattern state/mocking.
Show a summary per file
File Description
src/Microsoft.ComponentDetection.Common/PatternMatchingUtility.cs Introduces null-guarded public APIs, compiled matcher type, and uses FileSystemName.MatchesSimpleExpression for matching.
src/Microsoft.ComponentDetection.Contracts/IPathUtilityService.cs Restores MatchesPattern(pattern, fileName) on the contract as [Obsolete] for compatibility.
src/Microsoft.ComponentDetection.Common/PathUtilityService.cs Adds obsolete forwarding implementation to PatternMatchingUtility.MatchesPattern and removes old matching logic.
src/Microsoft.ComponentDetection.Common/SafeFileEnumerable.cs Removes stored search patterns and switches to a compiled matcher for include + matched-pattern selection.
src/Microsoft.ComponentDetection.Common/FastDirectoryWalkerFactory.cs Switches filtering and pattern attribution to compiled matcher usage; removes old per-pattern fanout logic.
test/Microsoft.ComponentDetection.Common.Tests/PatternMatchingUtilityTests.cs Updates matcher tests to new APIs and adds coverage for matching, compilation, GetMatchingPattern, and null guards.
test/Microsoft.ComponentDetection.Common.Tests/PathUtilityServiceTests.cs Adds coverage to ensure obsolete PathUtilityService.MatchesPattern forwards correctly.
test/Microsoft.ComponentDetection.Common.Tests/SafeFileEnumerableTests.cs Removes now-obsolete mocking of MatchesPattern since enumeration no longer uses it.
test/Microsoft.ComponentDetection.TestsUtilities/DetectorTestUtilityBuilder.cs Updates test pattern selection to use PatternMatchingUtility.GetMatchingPattern.

Copilot's findings

  • Files reviewed: 9/9 changed files
  • Comments generated: 2

@jpinz
Copy link
Copy Markdown
Member Author

jpinz commented Apr 8, 2026

@copilot apply changes based on the comments in this thread

Comment on lines +61 to +64
// Pattern priority is first-match-wins: earlier entries in searchPatterns
// are treated as higher priority when multiple patterns match.
var foundPattern = this.compiledMatcher.GetMatchingPattern(entry.FileName)
?? entry.FileName.ToString();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd mention it in the PR description alongside the case sensitivity note.

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 8, 2026

@copilot apply changes based on the comments in this thread

Applied in commit 836f45a: FastDirectoryWalkerFactory now reuses a single compiled matcher in GetFilteredComponentStreamObservable/subscribe path (no duplicate compile for the same pattern set), and PatternMatchingUtility now throws deterministically when a pattern collection contains null elements (with added tests). No UI changes in this PR, so there is no UI screenshot to provide.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • 1javsblobprodcus364.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/70C17A44F0DC17941F22F7FFA31FD262/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force conf�� by/62a16bed8d2ebf1c937cebce3f0299496694cfe33ba2a9d585d46c4a6e211db0 --global /home/REDACTED/.cargo/bin/git (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/3126A99D59DB84356F552B9BC0A2F062/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force conf�� assword=$GITHUB_TOKEN&#34;; }; f get/run/containerd/io.containerd.runtime.v2.task/moby/3c35ecdb72a01/tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet assword=$GITHUB_TOKEN&#34;; }; f get--log-format dotnet http.https://git/tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet (dns block)
  • 1p7vsblobprodcus324.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/A5E8D0CA472852830AF16B02D1DD7226/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force dotn�� by/62a16bed8d2ebf1c937cebce3f0299496694cfe33ba2a9d585d46c4a6e211db0 (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/70C17A44F0DC17941F22F7FFA31FD262/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force conf�� by/62a16bed8d2ebf1c937cebce3f0299496694cfe33ba2a9d585d46c4a6e211db0 --global /home/REDACTED/.cargo/bin/git (dns block)
  • 4myvsblobprodcus32.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/B9D91EC3F00925E83B2F176B451EEAFF/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/D47EE5A44C32F70BEBA9A6371300F374/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/CF4B41BED05CC519E28614CCFB1B4E53/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • 4vyvsblobprodcus361.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/A5E8D0CA472852830AF16B02D1DD7226/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force dotn�� by/62a16bed8d2ebf1c937cebce3f0299496694cfe33ba2a9d585d46c4a6e211db0 (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/70C17A44F0DC17941F22F7FFA31FD262/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force conf�� by/62a16bed8d2ebf1c937cebce3f0299496694cfe33ba2a9d585d46c4a6e211db0 --global /home/REDACTED/.cargo/bin/git (dns block)
  • 5dkvsblobprodcus355.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/86123D718A0A7D5E3D8DDB87D50A845A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • 5rqvsblobprodcus385.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/2D3586D8C912F6D195254B43F0F0042B/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/EAC58970BF56570ECF9A3336E1CC2C51/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/4EB20032E82B2584A5C53CFFE5CD470A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • 6s7vsblobprodcus313.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/D93C69A3F90DACDB68555AD6306FA9CB/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • 7tjvsblobprodcus341.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/CB9CBA9383D5A238E2B9DD721B214239/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • azuresdkartifacts.blob.core.windows.net
    • Triggering command: /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/csharp/tools/linux64/Semmle.Autobuild.CSharp /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/csharp/tools/linux64/Semmle.Autobuild.CSharp (dns block)
  • c78vsblobprodcus322.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/D93C69A3F90DACDB68555AD6306FA9CB/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/86123D718A0A7D5E3D8DDB87D50A845A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/C8FA87C461E8D947D5E484A1822A0126/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • fdpvsblobprodcus345.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/B20ADDE6A1C400383AAC6F21E747F83C/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force conf�� (dns block)
  • frdvsblobprodcus327.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/A576CF6326A01E4F0463D9C7ACE449BE/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force -c submodules | head -n 10 by/62a16bed8d2ebf1c937cebce3f0299496694cfe33ba2a9d585d46c4a6e211db0 ction/component-detection/test/Microsoft.ComponentDetection.Orchestrator.Tests/bin/Debug/net8.0/console by/62a16bed8d2eb/tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet 85d46c4a6e211db0restore (dns block)
  • k4kvsblobprodcus344.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/2D3586D8C912F6D195254B43F0F0042B/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/86123D718A0A7D5E3D8DDB87D50A845A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/4EB20032E82B2584A5C53CFFE5CD470A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • kmuvsblobprodcus389.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/A5E8D0CA472852830AF16B02D1DD7226/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force dotn�� by/62a16bed8d2ebf1c937cebce3f0299496694cfe33ba2a9d585d46c4a6e211db0 (dns block)
  • pdfvsblobprodcus380.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/C8FA87C461E8D947D5E484A1822A0126/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • s4uvsblobprodcus326.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/E2F72F1A2053363D6E348F396327EAB5/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force bin/�� detection/src/Microsoft.ComponentDetection.Contracts droid/34.0.43/ dotnet r (dns block)
  • v53vsblobprodcus320.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/3126A99D59DB84356F552B9BC0A2F062/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force conf�� assword=$GITHUB_TOKEN&#34;; }; f get/run/containerd/io.containerd.runtime.v2.task/moby/3c35ecdb72a01/tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet assword=$GITHUB_TOKEN&#34;; }; f get--log-format dotnet http.https://git/tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet (dns block)
  • vb4vsblobprodcus33.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/87542D29D2724C99BF713AC607C855F9/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force conf�� sdk-manifests/8.--package by/bbd8023e09de8microsoft.visualstudio.threading.analyzers dotnet by/bbd8023e09de8/tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet 944f8e4163012482restore (dns block)
  • ytvvsblobprodcus310.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/A57A5A89CDBA36A2878C8A42DA58182C/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title Address follow-up review feedback for centralized pattern matching migration Address follow-up review feedback for matcher reuse and null-pattern validation Apr 8, 2026
Copilot finished work on behalf of jpinz April 8, 2026 21:05
@jpinz jpinz requested a review from Copilot April 8, 2026 21:10
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the centralized file pattern-matching pipeline to reuse compiled matchers across filtering and matched-pattern selection, while making null-pattern handling deterministic and updating test coverage accordingly.

Changes:

  • Reuse a single compiled matcher in FastDirectoryWalkerFactory for both inclusion filtering and selecting the matched pattern.
  • Introduce deterministic ArgumentNullException behavior when any pattern element is null, and standardize matching via FileSystemName.MatchesSimpleExpression(..., ignoreCase: true).
  • Update and expand tests to cover matcher compilation, matching behavior, and null input validation.
Show a summary per file
File Description
src/Microsoft.ComponentDetection.Common/FastDirectoryWalkerFactory.cs Reuses one compiled matcher per subscription path and avoids recompiling patterns during filtered observable construction.
src/Microsoft.ComponentDetection.Common/PatternMatchingUtility.cs Adds Compile, MatchesPattern, GetMatchingPattern, and CompiledMatcher with deterministic null validation.
src/Microsoft.ComponentDetection.Common/SafeFileEnumerable.cs Switches to a compiled matcher for file inclusion and pattern attribution (and removes per-file pattern iteration).
src/Microsoft.ComponentDetection.Common/PathUtilityService.cs Removes local pattern matching logic and forwards (obsolete) MatchesPattern to PatternMatchingUtility.
src/Microsoft.ComponentDetection.Contracts/IPathUtilityService.cs Marks MatchesPattern obsolete and updates docs/parameter naming accordingly.
test/Microsoft.ComponentDetection.Common.Tests/PatternMatchingUtilityTests.cs Adds/updates tests for compiled matcher behavior, case-insensitivity, and null validation scenarios.
test/Microsoft.ComponentDetection.Common.Tests/PathUtilityServiceTests.cs Adds a test verifying obsolete PathUtilityService.MatchesPattern forwards to the new utility logic.
test/Microsoft.ComponentDetection.Common.Tests/SafeFileEnumerableTests.cs Removes mocks that are no longer relevant after SafeFileEnumerable no longer calls IPathUtilityService.MatchesPattern.
test/Microsoft.ComponentDetection.TestsUtilities/DetectorTestUtilityBuilder.cs Switches pattern selection to PatternMatchingUtility.GetMatchingPattern for consistency with production matching.

Copilot's findings

  • Files reviewed: 9/9 changed files
  • Comments generated: 2

@jpinz jpinz requested a review from Copilot April 8, 2026 21:41
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR centralizes wildcard pattern matching by introducing a compiled matcher API, reusing compiled matchers in directory scanning, and adding deterministic validation for null patterns (with tests updated accordingly).

Changes:

  • Replace ad-hoc/path-service pattern checks with PatternMatchingUtility + CompiledMatcher reuse to reduce repeated compilation and matching work.
  • Add deterministic ArgumentNullException behavior for null pattern inputs / null pattern elements.
  • Expand and adjust unit tests to cover Compile(...), MatchesPattern(...), and GetMatchingPattern(...) (including case-insensitivity and null validation).
Show a summary per file
File Description
test/Microsoft.ComponentDetection.TestsUtilities/DetectorTestUtilityBuilder.cs Swaps local matching logic to PatternMatchingUtility.GetMatchingPattern(...).
test/Microsoft.ComponentDetection.Common.Tests/SafeFileEnumerableTests.cs Updates tests to reflect matcher no longer calling IPathUtilityService.MatchesPattern(...).
test/Microsoft.ComponentDetection.Common.Tests/PatternMatchingUtilityTests.cs Adds coverage for compiled matcher, matching pattern selection, case-insensitivity, and null validation.
test/Microsoft.ComponentDetection.Common.Tests/PathUtilityServiceTests.cs Verifies obsolete PathUtilityService.MatchesPattern forwards to PatternMatchingUtility.
src/Microsoft.ComponentDetection.Contracts/IPathUtilityService.cs Updates doc/comments and marks MatchesPattern obsolete.
src/Microsoft.ComponentDetection.Common/SafeFileEnumerable.cs Replaces per-pattern iteration with a compiled matcher and pattern selection.
src/Microsoft.ComponentDetection.Common/PatternMatchingUtility.cs Introduces MatchesPattern, GetMatchingPattern, Compile, and CompiledMatcher using FileSystemName.MatchesSimpleExpression.
src/Microsoft.ComponentDetection.Common/PathUtilityService.cs Removes custom matching implementation; forwards obsolete API to PatternMatchingUtility.
src/Microsoft.ComponentDetection.Common/FastDirectoryWalkerFactory.cs Reuses a single compiled matcher for filtering + matched-pattern selection; adds subscribe overload.

Copilot's findings

  • Files reviewed: 9/9 changed files
  • Comments generated: 3

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors file pattern matching across the repo by centralizing matching logic in PatternMatchingUtility (with a reusable CompiledMatcher) and updating file enumeration to process each matched file once, using first-match pattern priority.

Changes:

  • Introduces PatternMatchingUtility.CompiledMatcher and span-based matching powered by FileSystemName.MatchesSimpleExpression (case-insensitive).
  • Updates directory walking/enumeration to select the first matching pattern per file and avoid duplicate ProcessRequest generation.
  • Modernizes and expands test coverage for matching semantics and null validation; marks IPathUtilityService.MatchesPattern as obsolete and forwards it.
Show a summary per file
File Description
test/Microsoft.ComponentDetection.TestsUtilities/DetectorTestUtilityBuilder.cs Uses PatternMatchingUtility.GetMatchingPattern instead of PathUtilityService.MatchesPattern in test utilities.
test/Microsoft.ComponentDetection.Common.Tests/SafeFileEnumerableTests.cs Removes mocks for MatchesPattern since matching no longer uses IPathUtilityService.
test/Microsoft.ComponentDetection.Common.Tests/PatternMatchingUtilityTests.cs Updates matcher tests to use Compile/CompiledMatcher and adds additional cases + null validation tests.
test/Microsoft.ComponentDetection.Common.Tests/PathUtilityServiceTests.cs Adds a regression test verifying the obsolete MatchesPattern forwards to PatternMatchingUtility.
src/Microsoft.ComponentDetection.Contracts/IPathUtilityService.cs Updates docs and marks MatchesPattern obsolete in favor of PatternMatchingUtility.
src/Microsoft.ComponentDetection.Contracts/FileComponentDetector.cs Documents first-match-wins priority for SearchPatterns.
src/Microsoft.ComponentDetection.Common/SafeFileEnumerable.cs Compiles patterns once and uses first-match-wins to assign a single pattern per matched file.
src/Microsoft.ComponentDetection.Common/PatternMatchingUtility.cs Adds MatchesPattern, GetMatchingPattern, and Compile APIs + CompiledMatcher implementation.
src/Microsoft.ComponentDetection.Common/PathUtilityService.cs Removes legacy matching implementations; obsolete method forwards to PatternMatchingUtility.
src/Microsoft.ComponentDetection.Common/FastDirectoryWalkerFactory.cs Reuses compiled matchers and emits one ProcessRequest per matching file with the selected pattern.

Copilot's findings

  • Files reviewed: 10/10 changed files
  • Comments generated: 1

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request continues the repo-wide refactor of file pattern matching to use PatternMatchingUtility.CompiledMatcher for reusable, case-insensitive matching, while updating callers/tests to align with the new “first match wins” semantics and improved null validation.

Changes:

  • Updates directory/file enumeration to compile and reuse matchers instead of re-evaluating patterns repeatedly.
  • Updates tests/utilities to use PatternMatchingUtility APIs and adds coverage for compilation, matching, and null-input validation.
  • Marks legacy IPathUtilityService.MatchesPattern as obsolete and forwards it to PatternMatchingUtility.
Show a summary per file
File Description
test/Microsoft.ComponentDetection.TestsUtilities/DetectorTestUtilityBuilder.cs Uses PatternMatchingUtility.GetMatchingPattern to determine the pattern associated with a file in tests.
test/Microsoft.ComponentDetection.Common.Tests/SafeFileEnumerableTests.cs Removes mocking of legacy MatchesPattern now that matching is handled via compiled matcher.
test/Microsoft.ComponentDetection.Common.Tests/PatternMatchingUtilityTests.cs Adds/updates tests for compiled matcher behavior, case-insensitivity, and null argument validation.
test/Microsoft.ComponentDetection.Common.Tests/PathUtilityServiceTests.cs Verifies obsolete PathUtilityService.MatchesPattern forwards to the new utility.
src/Microsoft.ComponentDetection.Contracts/IPathUtilityService.cs Updates docs and marks MatchesPattern obsolete in favor of PatternMatchingUtility.
src/Microsoft.ComponentDetection.Contracts/FileComponentDetector.cs Documents “first match wins” priority expectation for SearchPatterns.
src/Microsoft.ComponentDetection.Common/SafeFileEnumerable.cs Replaces per-pattern matching loops with a compiled matcher and uses first-match priority for MatchedFile.Pattern.
src/Microsoft.ComponentDetection.Common/PatternMatchingUtility.cs Introduces MatchesPattern, GetMatchingPattern, and CompiledMatcher backed by FileSystemName.MatchesSimpleExpression.
src/Microsoft.ComponentDetection.Common/PathUtilityService.cs Removes legacy matching logic and forwards obsolete MatchesPattern to the new utility.
src/Microsoft.ComponentDetection.Common/FastDirectoryWalkerFactory.cs Compiles patterns once per call and reuses the matcher for filtering and matched-pattern selection (avoids duplicate compilation).

Copilot's findings

  • Files reviewed: 10/10 changed files
  • Comments generated: 2

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR continues the pattern-matching refactor by introducing a reusable compiled matcher abstraction and wiring it through file enumeration and test utilities, while also tightening null validation and clarifying first-match priority semantics.

Changes:

  • Add PatternMatchingUtility.CompiledMatcher (span-based) and new helpers (Compile, MatchesPattern, GetMatchingPattern) backed by FileSystemName.MatchesSimpleExpression(ignoreCase: true).
  • Update file enumeration/filtering to compile patterns once and reuse the matcher; GetFilteredComponentStreamObservable now emits one ProcessRequest per file with the first matching pattern.
  • Update/expand unit tests and forward the obsolete IPathUtilityService.MatchesPattern to PatternMatchingUtility.
Show a summary per file
File Description
src/Microsoft.ComponentDetection.Common/PatternMatchingUtility.cs Introduces CompiledMatcher + null validation and span-based matching via FileSystemName.MatchesSimpleExpression.
src/Microsoft.ComponentDetection.Common/SafeFileEnumerable.cs Compiles patterns once per enumerable and uses first-match-wins for MatchedFile.Pattern.
src/Microsoft.ComponentDetection.Common/FastDirectoryWalkerFactory.cs Reuses a single compiled matcher and returns a single ProcessRequest per matching file (first matching pattern).
src/Microsoft.ComponentDetection.Common/PathUtilityService.cs Removes legacy matcher logic; obsolete MatchesPattern now forwards to PatternMatchingUtility.
src/Microsoft.ComponentDetection.Contracts/IPathUtilityService.cs Marks MatchesPattern obsolete and updates XML docs/parameter naming.
src/Microsoft.ComponentDetection.Contracts/FileComponentDetector.cs Updates SearchPatterns docs to reflect first-match priority and wildcard usage.
test/Microsoft.ComponentDetection.Common.Tests/PatternMatchingUtilityTests.cs Expands matching, case-insensitivity, null validation, and compiled matcher behaviors.
test/Microsoft.ComponentDetection.Common.Tests/SafeFileEnumerableTests.cs Adjusts mocks to reflect removal of IPathUtilityService.MatchesPattern usage.
test/Microsoft.ComponentDetection.Common.Tests/PathUtilityServiceTests.cs Verifies obsolete MatchesPattern forwarding behavior.
test/Microsoft.ComponentDetection.TestsUtilities/DetectorTestUtilityBuilder.cs Uses PatternMatchingUtility.GetMatchingPattern to select the effective pattern in tests.

Copilot's findings

  • Files reviewed: 10/10 changed files
  • Comments generated: 0 new

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.

4 participants