BrighterCommand / BrighterCommand/Brighter

CI guard: fail the build when a `.csproj` is not referenced by `Brighter.slnx`

Open
#4,273 0 comments 0 reactions 1 assignee Claimed by @iancooper View on GitHub
.NET 0 - Backlog Bug Maintenance
Dominant language
C#
Stars
2.5k
Forks
296
Avg merge
1d 11h
Merged PRs (30d)
21

Description

A project can sit under `samples/`, compile perfectly for anyone who opens it, and still never
be built by CI — because CI builds `Brighter.slnx` and the project was never added to it.

That happened with `TodoApi` (#4272): it went in with #3953 on 2026-02-01 and was still
unreferenced roughly six months later.

### Why it goes unnoticed

A missing solution entry is invisible from every direction anyone actually looks:

- the file is in the right directory, so a listing looks correct
- it compiles when opened in an IDE, so the author sees it work
- **CI cannot go red over it** — a project outside the solution cannot fail the build
- no output anywhere says *"and one project was skipped"*

The failure mode is silence, and silence is indistinguishable from success. The only way to
find it is to compare two lists nobody has a reason to compare.

### Suggested guard

```bash
diff <(git ls-files '*.csproj' | sort) \
<(grep -o 'Path="[^"]*\.csproj"' Brighter.slnx | sed 's/Path="//;s/"//' | sort)
```

Run against `master` today this prints exactly one line — `TodoApi` — and exits 1. Once that
is registered it is clean, so it can go straight into `ci.yml` as a step.

Two details that are worth keeping if you rewrite it, because both cost me a wrong answer
first:

- **`git ls-files`, not `find`.** `find` reads the working filesystem, which picks up
`bin/`/`obj/` copies and untracked scratch projects. It also reports whatever casing the
local filesystem has: on a case-insensitive macOS checkout `find` shows
`src/Paramore.Brighter.MessageScheduler.Aws` while the repository — and Linux CI — has
`.AWS`. A naive `find`-based diff therefore reports phantom mismatches that do not exist on
the runner. `git ls-files` reports what the repository contains.
- **Scope the whole repo, not just `samples/`.** `.csproj` files live under `benchmarks/`,
`samples/`, `src/`, `tests/` and `tools/`, and the solution references all five. An
unregistered *test* project is worse than an unregistered sample — it is a suite that
reports nothing rather than failing.

One decision I did not want to make for you: **whether a deliberate exclusion needs an escape
hatch.** If some project is intentionally out of the solution, the guard wants an allowlist or
it becomes a check people learn to ignore. If none exist, it can stay strict, which is better.

Happy to open a PR once the scope and the allowlist question are settled.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.