Skip to content

Conversation

rocklan
Copy link

@rocklan rocklan commented Jun 4, 2025

This PR adds support for being able to specify a list of dotnet solution filter files, and for those files to be parsed and converted to Yaml file patterns.

What this means in english is that if we have a solution filter file in our repo that looks like this:

MyApplication.slnf

{
  "solution": {
    "path": "MyApplication.sln",
    "projects": [
      "MyApplication.Web\\MyApplication.Web.csproj",
      "MyApplication.Logic\\MyApplication.Logic.csproj",
      "MyApplication.Tests\\MyApplication.Tests.csproj"
    ]
  }
}

and we supply it as an input parameter to this action:

      - name: Get changed files
        id: changed-files
        uses: rome2rio/changed-files@lachlan/solutionfilters
        with:
          solution_filters: "MyApplication.slnf"

it will be treated like a configuration yaml file that looks like so:

myapplication:
  - MyApplication.Web/**
  - MyApplication.Logic/**
  - MyApplication.Tests/**

This is great because it means our changed_files.yaml file doesn't need to be manually kept in sync with our solution filters. If we add a new project to a solution or delete/rename a project it will automatically be picked up by changed-files. This may seem like a trivial request but the larger the repo the bigger this problem becomes, and adding this feature would simplify a lot of things. Currently we are generating this file as a separate step (and caching it) but it all becomes a lot simpler if it's just done inside this action.

The way it works is by parsing the slnf file specified, looking for the projects array inside the file, then looking for .csproj file references, and then filtering out the project file but keeping the path. Once we have the path, we append /** to the end of it and we have our filePattern. The key added is the name of the solution filter file converted to lowercase (and dots converted to dashes).

This also provides great support for monorepos, because if you specify multiple solution filters, they will also be added to the configuration:

myapplication:
  - MyApplication.Web/**
  - MyApplication.Logic/**
  - MyApplication.Tests/**
myotherapplication:  
  - subdir/MyOtherApplication.Console/**

Plus, if you have extra files that are outside of the project directory, you can specify them in a yaml file and they will be appended:

project-files.yml

# Do not add any project directories to this file as they are added automatically by changed-files
myapplication:
  - some-other-directory
myotherapplication:
  - README.md

which will end up giving us:

myapplication:
  - some-other-directory
  - MyApplication.Web/**
  - MyApplication.Logic/**
  - MyApplication.Tests/**
myotherapplication:  
  - README.md
  - subdir/MyOtherApplication.Console/**

The code submitted is definitely not awesome, all reviews extremely welcome :) I suspect this feature would be really helpful to a lot of .NET devs.

@jackton1
Copy link
Contributor

bugbot run

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Bug: Key Generation and Path Separator Issues

The code has two issues when processing solution filters:

  1. Key Generation: The key generation uses replace('.', '-'), which only replaces the first occurrence of a dot in the solution filter filename. This results in incorrect keys for filenames with multiple dots (e.g., "My.Project.Solution.slnf" becomes "My-Project.Solution" instead of "My-Project-Solution"). A global replace (.replace(/\./g, '-')) is required.
  2. Path Handling: The logic for extracting project directory names (project.lastIndexOf('\\')) assumes Windows-style backslash path separators. If project paths in the solution filter use forward slashes (common on non-Windows systems), this logic fails, causing valid .csproj files to be skipped and incorrect include strings to be generated. The code should handle both path separators or normalize paths.

src/utils.ts#L1311-L1320

changed-files/src/utils.ts

Lines 1311 to 1320 in 091153e

// Exclude the project name so we can get the directory name
const directoryName = project.substring(0, project.lastIndexOf('\\'))
core.debug(`Found directory name: ${directoryName}`)
// If the project item ends with a .csproj (just extra safety)
if (project.endsWith('.csproj') && project.lastIndexOf('\\') !== -1) {
let includeString = `${directoryName.replace(/\\/g, '/')}/**`
let key: string = solutionFilter.filename
.replace('.slnf', '')
.replace('.', '-')

Fix in CursorFix in Web


Bug: Solution Filter Overwrites Project Patterns

When processing solution filters, the filePatterns array is incorrectly overwritten for each project within the same solution filter. This results in only the last project's directory pattern being retained for a given solution filter key, effectively losing all other projects from that same filter. The intended behavior is to accumulate all project directory patterns under a single key.

src/utils.ts#L1338-L1339

changed-files/src/utils.ts

Lines 1338 to 1339 in 091153e

core.debug(` Adding ${key} with include string: ${includeString}`)
filePatterns[key] = [includeString]

Fix in CursorFix in Web


Learn more in the Cursor dashboard.

Was this report helpful? Give feedback by reacting with 👍 or 👎

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