build(public): fail build when src/public/ project lacks README.md #31

Merged
jasoncouture merged 1 commit from feat/public-readme-required into main 2026-05-07 11:38:52 -04:00
jasoncouture commented 2026-05-07 10:55:59 -04:00 (Migrated from github.com)

Summary

Pit-of-success enforcement of the existing "every package under src/public/ ships a README.md" rule. Resolves the TASKS.md item under Build / infrastructure (line 79).

What's in here

New file: src/public/Directory.Build.targets defining LlamaShearsValidatePublicReadme (runs BeforeTargets="CoreCompile", skipped on DesignTimeBuild):

  • LSPUB0001README.md is missing for a project under src/public/.
  • LSPUB0002README.md exists but its content is empty / whitespace-only.

The targets file imports the parent Directory.Build.targets first, so the existing LlamaShears.DocsBuild wiring (which already references README.md when present) continues to apply unchanged for every src/public/ project.

Why an MSBuild error and not a docs-build assertion

The docs-build target already does Exists('$(MSBuildProjectDirectory)\README.md') and shrugs when absent (_LlamaShearsAssemblyReadme stays empty). That kept the docs build robust to projects without a readme — but it also meant a new public package could ship with no NuGet readme and no docs/api lead-in without anyone noticing. Promoting the missing/empty case to a hard build error closes that gap.

The check is in src/public/Directory.Build.targets rather than the docs-build targets so the scope is the location-driven packable contract, not the doc generator. A future packable project outside src/public/ (if that ever happens) would need its own opt-in.

Test plan

  • dotnet build LlamaShears.slnx — clean, 0 warnings, 0 errors.
  • Negative case 1 (missing README): temporarily removed src/public/LlamaShears.Core.Abstractions.Paths/README.md, build emitted error LSPUB0001 and failed.
  • Negative case 2 (whitespace-only README): replaced contents with \n\n \t\n, build emitted error LSPUB0002 and failed.
  • Positive case after restore: build clean.
  • Husky docs-api-up-to-date pre-push check passed.

🤖 Generated with Claude Code

## Summary Pit-of-success enforcement of the existing "every package under `src/public/` ships a `README.md`" rule. Resolves the TASKS.md item under *Build / infrastructure* (line 79). ## What's in here New file: `src/public/Directory.Build.targets` defining `LlamaShearsValidatePublicReadme` (runs `BeforeTargets="CoreCompile"`, skipped on `DesignTimeBuild`): - **`LSPUB0001`** — `README.md` is missing for a project under `src/public/`. - **`LSPUB0002`** — `README.md` exists but its content is empty / whitespace-only. The targets file imports the parent `Directory.Build.targets` first, so the existing `LlamaShears.DocsBuild` wiring (which already references `README.md` when present) continues to apply unchanged for every `src/public/` project. ## Why an MSBuild error and not a docs-build assertion The docs-build target already does `Exists('$(MSBuildProjectDirectory)\README.md')` and shrugs when absent (`_LlamaShearsAssemblyReadme` stays empty). That kept the docs build robust to projects without a readme — but it also meant a new public package could ship with no NuGet readme and no `docs/api` lead-in without anyone noticing. Promoting the missing/empty case to a hard build error closes that gap. The check is in `src/public/Directory.Build.targets` rather than the docs-build targets so the scope is the *location-driven packable contract*, not the doc generator. A future packable project outside `src/public/` (if that ever happens) would need its own opt-in. ## Test plan - [x] `dotnet build LlamaShears.slnx` — clean, 0 warnings, 0 errors. - [x] Negative case 1 (missing README): temporarily removed `src/public/LlamaShears.Core.Abstractions.Paths/README.md`, build emitted `error LSPUB0001` and failed. - [x] Negative case 2 (whitespace-only README): replaced contents with ` \n\n \t\n`, build emitted `error LSPUB0002` and failed. - [x] Positive case after restore: build clean. - [x] Husky `docs-api-up-to-date` pre-push check passed. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
CLAassistant commented 2026-05-07 10:56:11 -04:00 (Migrated from github.com)

CLA assistant check
All committers have signed the CLA.

[![CLA assistant check](https://cla-assistant.io/pull/badge/signed)](https://cla-assistant.io/jasoncouture/llama-shears?pullRequest=31) <br/>All committers have signed the CLA.
copilot-pull-request-reviewer[bot] (Migrated from github.com) reviewed 2026-05-07 10:59:44 -04:00
copilot-pull-request-reviewer[bot] (Migrated from github.com) left a comment

Pull request overview

Adds an MSBuild “pit-of-success” enforcement for projects under src/public/ to ensure they always ship a non-empty README.md, aligning public package expectations with the existing docs generation behavior.

Changes:

  • Introduces src/public/Directory.Build.targets that runs a pre-compile validation target for README.md.
  • Fails the build with specific error codes when README.md is missing (LSPUB0001) or whitespace-only (LSPUB0002).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

## Pull request overview Adds an MSBuild “pit-of-success” enforcement for projects under `src/public/` to ensure they always ship a non-empty `README.md`, aligning public package expectations with the existing docs generation behavior. **Changes:** - Introduces `src/public/Directory.Build.targets` that runs a pre-compile validation target for `README.md`. - Fails the build with specific error codes when `README.md` is missing (`LSPUB0001`) or whitespace-only (`LSPUB0002`). --- 💡 <a href="/jasoncouture/llama-shears/new/main?filename=.github/instructions/*.instructions.md" class="Link--inTextBlock" target="_blank" rel="noopener noreferrer">Add Copilot custom instructions</a> for smarter, more guided reviews. <a href="https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot" class="Link--inTextBlock" target="_blank" rel="noopener noreferrer">Learn how to get started</a>.
@ -0,0 +23,4 @@
<PropertyGroup Condition=" Exists('$(_LlamaShearsPublicReadmePath)') ">
<_LlamaShearsPublicReadmeContent>$([System.IO.File]::ReadAllText('$(_LlamaShearsPublicReadmePath)').Trim())</_LlamaShearsPublicReadmeContent>
</PropertyGroup>
copilot-pull-request-reviewer[bot] (Migrated from github.com) commented 2026-05-07 10:59:44 -04:00

_LlamaShearsPublicReadmePath uses a Windows-style \ path separator, and that string is then passed into System.IO.File::ReadAllText(...). On non-Windows builds, ReadAllText won’t treat \ as a directory separator, so this can throw/file-not-found even when README.md exists. Use a cross-platform path (e.g., $(MSBuildProjectDirectory)/README.md or System.IO.Path::Combine('$(MSBuildProjectDirectory)','README.md'), optionally wrapped with MSBuild path normalization) before calling ReadAllText.

`_LlamaShearsPublicReadmePath` uses a Windows-style `\` path separator, and that string is then passed into `System.IO.File::ReadAllText(...)`. On non-Windows builds, `ReadAllText` won’t treat `\` as a directory separator, so this can throw/file-not-found even when README.md exists. Use a cross-platform path (e.g., `$(MSBuildProjectDirectory)/README.md` or `System.IO.Path::Combine('$(MSBuildProjectDirectory)','README.md')`, optionally wrapped with MSBuild path normalization) before calling `ReadAllText`.
Sign in to join this conversation.
No description provided.