diff --git a/.husky/pre-commit b/.husky/pre-commit index 818853f..61e766f 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,39 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" +# Local lint checks with the fleet-standard set, so a commit never surprises the maintainer with a CI-only failure +# (line endings, workflow YAML, Markdown, spelling). It runs the fleet-standard lint tools through Docker so they +# behave identically across Windows, WSL, and Linux. To keep the hook reliable and never a false blocker it +# only runs an image already present locally (never pulls) and skips when Docker or the image is unavailable - +# CI is still the gate for whatever lint it runs. Warm the images once with the VS Code "Lint" tasks. MSYS_NO_PATHCONV keeps the +# bind mount correct under Git Bash on Windows; it is a no-op on Linux/WSL. + +# C# formatting + style (CSharpier + dotnet format) via task-runner.json. .NET repos only - drop this line otherwise. dotnet husky run + +lint() { + image="$1" + shift + if command -v docker >/dev/null 2>&1 && docker image inspect "$image" >/dev/null 2>&1; then + MSYS_NO_PATHCONV=1 docker run --rm -v "$(pwd):/check" -w /check "$image" "$@" || exit 1 + else + echo "husky: $image not available (Docker not running or image absent), skipping - CI enforces it" + fi +} + +staged=$(git diff --cached --name-only --diff-filter=ACMR) + +# Line endings / charset across the tree - the editorconfig-checker gate that catches a mis-ended file (e.g. a +# new codecov.yml committed with LF where the repo is CRLF). +lint mstruebing/editorconfig-checker@sha256:67b9e9b16a674e36f7c05919da789f03a01d343ca8423eb8797179399af07c00 + +# Workflow YAML (plus embedded run: shell via bundled shellcheck) when a workflow file is staged. +if printf '%s\n' "$staged" | grep -Eq '^\.github/workflows/.*\.ya?ml$'; then + lint rhysd/actionlint:latest -color +fi + +# Markdown lint + spelling (word list + exclusions from cspell.json) when a Markdown file is staged. +if printf '%s\n' "$staged" | grep -q '\.md$'; then + lint davidanson/markdownlint-cli2:latest "**/*.md" + lint ghcr.io/streetsidesoftware/cspell:latest --no-progress README.md HISTORY.md +fi diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 10e227c..24a521e 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -142,6 +142,59 @@ "CSharpier Format" ], "problemMatcher": [] + }, + // Lint group - runs the fleet-standard lint set locally and warms + // the Docker images the .husky/pre-commit hook reuses. Language-agnostic; every repo carries these. + { + "label": "Lint: Line Endings", + "type": "shell", + "command": "docker run --rm -v \"${workspaceFolder}:/check\" -w /check mstruebing/editorconfig-checker@sha256:67b9e9b16a674e36f7c05919da789f03a01d343ca8423eb8797179399af07c00", + "problemMatcher": [], + "presentation": { + "showReuseMessage": false, + "clear": false + } + }, + { + "label": "Lint: Workflows", + "type": "shell", + "command": "docker run --rm -v \"${workspaceFolder}:/repo\" -w /repo rhysd/actionlint:latest -color", + "problemMatcher": [], + "presentation": { + "showReuseMessage": false, + "clear": false + } + }, + { + "label": "Lint: Markdown", + "type": "shell", + "command": "docker run --rm -v \"${workspaceFolder}:/workdir\" -w /workdir davidanson/markdownlint-cli2:latest \"**/*.md\"", + "problemMatcher": [], + "presentation": { + "showReuseMessage": false, + "clear": false + } + }, + { + "label": "Lint: Spelling", + "type": "shell", + "command": "docker run --rm -v \"${workspaceFolder}:/workdir\" -w /workdir ghcr.io/streetsidesoftware/cspell:latest --no-progress README.md HISTORY.md", + "problemMatcher": [], + "presentation": { + "showReuseMessage": false, + "clear": false + } + }, + { + "label": "Lint: All", + "dependsOrder": "sequence", + "dependsOn": [ + "Lint: Line Endings", + "Lint: Workflows", + "Lint: Markdown", + "Lint: Spelling" + ], + "problemMatcher": [] } ] } diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..eff9a54 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,19 @@ +# Codecov configuration. Coverage is reported and trended, never gated: +# informational: true keeps Codecov's project and patch commit statuses +# advisory (always pass) so a coverage delta can never block a PR - a distinct +# knob from the upload step's fail_ci_if_error: false, which only guards upload +# errors. A repo may override this to enforce a coverage threshold. +coverage: + status: + project: + default: + informational: true + patch: + default: + informational: true + +# Exclude code intentionally not unit-tested from the coverage denominator - +# e.g. an example/demo console app or a benchmark project, not the shipped +# library. Add the repo's own paths. +# ignore: +# - "Sandbox/**"