I've been building a .NET toolchain plugin (moonrepo/plugins#169), and this is the one part I couldn't solve from inside a plugin.
Some context, since it's specific to how .NET lays repos out. A project is a .csproj file, its name is arbitrary, and it normally sits a level or two below anything you'd want to glob for, something like src/Billing/Billing.Service/Billing.Service.csproj. There's no moon.yml-shaped marker to key off, and the directory names on their own aren't reliable either.
Today projects.globs matches directories or moon.yml files. Anything else gets dropped with a warning rather than an error (2.4.5):
WARN moon_workspace::projects_locator Received a file path for a project root, must be a directory source="...\src\Foo\Foo.csproj"
So src/**/*.csproj silently gives you nothing.
A plugin can't fill the gap either. An id returned from extend_project_graph that isn't already declared fails with UnconfiguredID (crates/workspace/src/projects_builder.rs). That makes sense given the design, but it does mean discovery is the one part of a language integration a toolchain can't supply.
What's left is listing every project directory in workspace.yml by hand, which doesn't scale to a real solution. Of the repos I tested the plugin against, OrchardCore would need 238 entries and abp 671. A glob like src/*/* gets close in a tidy repo, but ids come from directory basenames, and names like Tests repeat across services in most .NET solutions, so they collide. In practice you either generate the map or drop an empty moon.yml stub in every project directory purely to mark it.
Two ways I can see to fix it:
- Let
projects.globs match arbitrary marker files, so src/**/*.csproj declares the containing directory as a project. Ids would still need a rule, probably the directory name plus some way out of collisions.
- Let toolchains contribute projects, say a
locate_projects returning id and source pairs, so each ecosystem picks its own naming.
1 looks smaller, and it'd help anything whose marker isn't moon.yml: Cargo.toml, go.mod, pyproject.toml, *.csproj. 2 is more work but would let ids come from something better than a directory name, which for .NET would be the project filename or the evaluated AssemblyName.
Interested in what you think, and whether there's an option I'm not seeing here. If it's not something you'd want to pick up yourself, I could have a look at a PR.
I've been building a .NET toolchain plugin (moonrepo/plugins#169), and this is the one part I couldn't solve from inside a plugin.
Some context, since it's specific to how .NET lays repos out. A project is a
.csprojfile, its name is arbitrary, and it normally sits a level or two below anything you'd want to glob for, something likesrc/Billing/Billing.Service/Billing.Service.csproj. There's nomoon.yml-shaped marker to key off, and the directory names on their own aren't reliable either.Today
projects.globsmatches directories ormoon.ymlfiles. Anything else gets dropped with a warning rather than an error (2.4.5):So
src/**/*.csprojsilently gives you nothing.A plugin can't fill the gap either. An id returned from
extend_project_graphthat isn't already declared fails withUnconfiguredID(crates/workspace/src/projects_builder.rs). That makes sense given the design, but it does mean discovery is the one part of a language integration a toolchain can't supply.What's left is listing every project directory in
workspace.ymlby hand, which doesn't scale to a real solution. Of the repos I tested the plugin against, OrchardCore would need 238 entries and abp 671. A glob likesrc/*/*gets close in a tidy repo, but ids come from directory basenames, and names likeTestsrepeat across services in most .NET solutions, so they collide. In practice you either generate the map or drop an emptymoon.ymlstub in every project directory purely to mark it.Two ways I can see to fix it:
projects.globsmatch arbitrary marker files, sosrc/**/*.csprojdeclares the containing directory as a project. Ids would still need a rule, probably the directory name plus some way out of collisions.locate_projectsreturning id and source pairs, so each ecosystem picks its own naming.1 looks smaller, and it'd help anything whose marker isn't
moon.yml:Cargo.toml,go.mod,pyproject.toml,*.csproj. 2 is more work but would let ids come from something better than a directory name, which for .NET would be the project filename or the evaluatedAssemblyName.Interested in what you think, and whether there's an option I'm not seeing here. If it's not something you'd want to pick up yourself, I could have a look at a PR.