diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 1ceed0f..7eed14f 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -7,13 +7,18 @@ name: Site # # Node 24 is a floor, not a preference: the build and prerender scripts are # TypeScript run straight by node, which needs its type stripping. +# +# The artifact also carries the coverage report, which is why a change to any +# Go file rebuilds the site: coverage is the library's number, so it moves +# when the library or its tests do, and narrowing these paths back to site/ +# would leave the badge reading a figure from whenever the site last changed. on: push: branches: [main] - paths: [site/**, examples/guide/**, .github/workflows/pages.yml] + paths: [site/**, examples/guide/**, "**/*.go", go.mod, .github/workflows/pages.yml] pull_request: - paths: [site/**, examples/guide/**, .github/workflows/pages.yml] + paths: [site/**, examples/guide/**, "**/*.go", go.mod, .github/workflows/pages.yml] workflow_dispatch: permissions: @@ -28,6 +33,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 + - uses: actions/setup-go@v6 + with: + go-version-file: go.mod + check-latest: true - uses: actions/setup-node@v5 with: node-version: 24 @@ -41,6 +50,24 @@ jobs: working-directory: site env: BASE_PATH: /di + # Written into the built site rather than served from anywhere else, so + # the report and the badge it links from are one deploy and cannot + # disagree. The profile covers di, dihttp and dislog: examples/ and + # benchmarks/ are separate modules and not part of the number. + - name: coverage report and badge, into the artifact + run: | + go test -count=1 -coverprofile=coverage.out ./... + go tool cover -html=coverage.out -o site/build/coverage.html + pct=$(go tool cover -func=coverage.out | tail -1 | awk '{print $NF}') + n=${pct%\%} + color=red + awk -v n="$n" 'BEGIN { exit !(n >= 90) }' && color=brightgreen + awk -v n="$n" 'BEGIN { exit !(n >= 80 && n < 90) }' && color=green + awk -v n="$n" 'BEGIN { exit !(n >= 70 && n < 80) }' && color=yellowgreen + awk -v n="$n" 'BEGIN { exit !(n >= 60 && n < 70) }' && color=yellow + printf '{"schemaVersion":1,"label":"coverage","message":"%s","color":"%s"}\n' \ + "$pct" "$color" > site/build/coverage.json + echo "coverage $pct ($color)" - uses: actions/upload-pages-artifact@v4 with: path: site/build diff --git a/CLAUDE.md b/CLAUDE.md index 5ca81d2..d27b578 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -592,6 +592,16 @@ reverse is caught by the fuzzer in 0.06s and *not* by the 400 seeded sequences. - **README code blocks are generated.** They are embedded from `examples/` with embedmd markers. Run `gofmt -w` on an example *before* re-embedding, or CI fails on the sync check. +- **Coverage is published with the site, not to a service.** `pages.yml` + writes `go tool cover -html` and a shields endpoint JSON into `site/build` + before uploading the artifact, so the report at + `floatdrop.github.io/di/coverage.html` and the badge that links to it are + one deploy and cannot disagree. It covers `di`, `dihttp` and `dislog`: the + two separate modules are not part of the library's number. **That is why the + site workflow's path filter includes `**/*.go`** -- coverage moves when the + library or its tests do, and narrowing the paths back to `site/` would leave + the badge reading a figure from whenever the site last changed, with nothing + failing to say so. - **`examples/` and `benchmarks/` are separate modules**, each with a `replace ../` directive, so the root module keeps zero requires and the library's "no dependency outside the standard library" claim stays true. diff --git a/README.md b/README.md index 83e1c56..11c505a 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![CI](https://github.com/floatdrop/di/actions/workflows/ci.yml/badge.svg)](https://github.com/floatdrop/di/actions/workflows/ci.yml) [![Go Reference](https://pkg.go.dev/badge/github.com/floatdrop/di.svg)](https://pkg.go.dev/github.com/floatdrop/di) +[![coverage](https://img.shields.io/endpoint?url=https%3A%2F%2Ffloatdrop.github.io%2Fdi%2Fcoverage.json)](https://floatdrop.github.io/di/coverage.html) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) A dependency-injection container for Go 1.27+. Constructors are plain diff --git a/site/README.md b/site/README.md index 3a302bf..e36d71f 100644 --- a/site/README.md +++ b/site/README.md @@ -83,7 +83,7 @@ Add its id to `StepId`, then add the step to `steps` in **every** locale; `tsc` will not let you forget one. If it shows a new file, add the id to `FigureId`, the import to `src/code.ts`, and the figure to `buildFigures`. -## Seven things worth knowing +## Eight things worth knowing `src/inline-script.ts` is inlined by calling `Function.prototype.toString` on it, so it is cut out of its module and must close over nothing: everything it @@ -132,3 +132,13 @@ Gravity UI's own `styles/fonts.css` pulls Inter from Google Fonts. Nothing third-party is on the path to rendering the page, so `src/styles/main.css` overrides the font stack instead; there is a comment there saying how to get Inter back. + +`site/build` is not only the site. `pages.yml` writes `coverage.html` and +`coverage.json` into it after `npm run build` and before the artifact is +uploaded, so the coverage report is served by the same deploy as the pages +that link to it. Two consequences: a local `npm run build` gives a tree +without them, and the report is the one thing on this site no local build +reproduces; and the workflow's path filter has `**/*.go` in it, so a change to +Go code deploys the site. Narrow that filter back to `site/` and the badge in +the root README goes on reading a figure from whenever the site last changed, +with nothing failing to say so.