diff --git a/.github/workflows/validate-task.yml b/.github/workflows/validate-task.yml index 151cbfb..34bc502 100644 --- a/.github/workflows/validate-task.yml +++ b/.github/workflows/validate-task.yml @@ -81,5 +81,5 @@ jobs: - name: Lint workflows step uses: raven-actions/actionlint@3d39aea434753780c3b3d4a1a31c854b4dbf49d7 # v2.2.0 - - name: Check line endings step - run: docker run --rm -v "$PWD":/check --workdir /check mstruebing/editorconfig-checker@sha256:67b9e9b16a674e36f7c05919da789f03a01d343ca8423eb8797179399af07c00 # editorconfig-checker v3.4.0 + - name: Check EditorConfig step + run: docker run --rm -v "$PWD":/check --workdir /check mstruebing/editorconfig-checker:latest diff --git a/.husky/pre-commit b/.husky/pre-commit index 818853f..e9a75d5 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,9 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" -dotnet husky run +# Local pre-commit: language formatting and style only (no Docker). Full lint runs in CI and the VS Code Lint tasks. + +# .NET: CSharpier + dotnet format style via Husky.Net. A Python repo runs ruff here instead. +if command -v dotnet >/dev/null 2>&1; then + dotnet husky run +fi diff --git a/.vscode/tasks.json b/.vscode/tasks.json index d1ffb6b..5eee7e9 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -132,6 +132,63 @@ "showReuseMessage": false, "clear": false } + }, + // Lint group - the local full doc-lint surface (Docker at :latest), matching the CI lint set. + // Run on demand. The pre-commit hook does language formatting only. Every repo carries these. + { + "label": "Lint: EditorConfig", + "type": "process", + "command": "docker", + "args": [ "run", "--rm", "--pull=always", "-v", "${workspaceFolder}:/check", "-w", "/check", "mstruebing/editorconfig-checker:latest" ], + "problemMatcher": [], + "presentation": { + "showReuseMessage": false, + "clear": false + } + }, + { + "label": "Lint: Workflows", + "type": "process", + "command": "docker", + "args": [ "run", "--rm", "--pull=always", "-v", "${workspaceFolder}:/repo", "-w", "/repo", "rhysd/actionlint:latest", "-color" ], + "problemMatcher": [], + "presentation": { + "showReuseMessage": false, + "clear": false + } + }, + { + "label": "Lint: Markdown", + "type": "process", + "command": "docker", + "args": [ "run", "--rm", "--pull=always", "-v", "${workspaceFolder}:/workdir", "-w", "/workdir", "davidanson/markdownlint-cli2:latest", "**/*.md" ], + "problemMatcher": [], + "presentation": { + "showReuseMessage": false, + "clear": false + } + }, + { + "label": "Lint: Spelling", + "type": "process", + "command": "docker", + "args": [ "run", "--rm", "--pull=always", "-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: EditorConfig", + "Lint: Workflows", + "Lint: Markdown", + "Lint: Spelling" + ], + "problemMatcher": [] } ] } diff --git a/AGENTS.md b/AGENTS.md index dfab58b..4507001 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -159,7 +159,7 @@ Anti-pattern: don't keep flipping the code on the same style point. Flip the rul - **Config files.** [`.editorconfig`](./.editorconfig) (per-file-type EOL plus the C# / ReSharper style block), [`.gitattributes`](./.gitattributes), [`.markdownlint-cli2.jsonc`](./.markdownlint-cli2.jsonc), [`CODESTYLE.md`](./CODESTYLE.md) (C# code style), and [`.github/copilot-instructions.md`](./.github/copilot-instructions.md) (the Copilot review runbook) hold the repo's formatting, linting, and review-mechanics rules. `CODESTYLE.md` sits at the repo root because `AGENTS.md` and `copilot-instructions.md` link it by relative path. Keep `copilot-instructions.md` narrow (Copilot/VS Code mechanics plus the commit/PR-title summary); project-specific conventions and the public-API contract live in this file, not there. - **Clean-compile gate.** Husky.Net pre-commit git hooks run the C# clean-compile checks (CSharpier format, then `dotnet format style --verify-no-changes`), installed with `dotnet tool restore` + `dotnet husky install`. The [`.vscode/tasks.json`](./.vscode/tasks.json) tasks `.NET Build`, `CSharpier Format`, and `.NET Format` are the canonical task names (owned by the `CODESTYLE.md` ".NET" section); do not loosen them. CI is the authoritative backstop: the `lint` job ([`WORKFLOW.md`](./WORKFLOW.md) D1.3) enforces CSharpier, `dotnet format style`, `markdownlint`, scoped `cspell`, and `actionlint` from the same config files, because a local hook can be bypassed. Keep the editor task, the hook, and CI in sync (CODESTYLE "Clean-Compile Verification"). -- **Linting tools.** CI is the authoritative lint run; a local run is only for fast feedback. The `dotnet` checks need only the .NET SDK: `dotnet format style` is built into the SDK, and CSharpier is restored by `dotnet tool restore` against [`.config/dotnet-tools.json`](./.config/dotnet-tools.json). The markdown, spelling, and workflow linters have no committed manifest; run each from its official Docker image, the portable path that avoids a local Node or Go install, mounting the repo as the working directory: `cspell` from `ghcr.io/streetsidesoftware/cspell`, `markdownlint-cli2` from `davidanson/markdownlint-cli2`, and `actionlint` (which bundles `shellcheck`) from `rhysd/actionlint`, pinned to the versions [`validate-task.yml`](./.github/workflows/validate-task.yml) uses. Each takes the file globs directly, for example `docker run --rm -v "$PWD":/work -w /work ghcr.io/streetsidesoftware/cspell cspell README.md HISTORY.md` or `... davidanson/markdownlint-cli2 '**/*.md'`. The cspell accepted-word list and the path exclusions both live in [`cspell.json`](./cspell.json), the single source: the Code Spell Checker extension reads `cspell.json` ahead of the workspace `cSpell` settings (so GUI "Add to dictionary" lands words there), and the CLI and CI read the same file. Do not keep a parallel word list in the `.code-workspace` file. A local cspell or markdownlint result that reports zero files checked scanned nothing; ignore it. There is intentionally no wrapper script; the editor, these Docker images, and CI are the supported runners. +- **Linting tools.** CI is the authoritative lint run; a local run is only for fast feedback. The `dotnet` checks need only the .NET SDK: `dotnet format style` is built into the SDK, and CSharpier is restored by `dotnet tool restore` against [`.config/dotnet-tools.json`](./.config/dotnet-tools.json). The markdown, spelling, and workflow linters have no committed manifest; run each from its official Docker image, the portable path that avoids a local Node or Go install, mounting the repo as the working directory: `cspell` from `ghcr.io/streetsidesoftware/cspell`, `markdownlint-cli2` from `davidanson/markdownlint-cli2`, and `actionlint` (which bundles `shellcheck`) from `rhysd/actionlint`, at `:latest`. CI runs these three as pinned action wrappers (Dependabot bumps them) and editorconfig-checker via Docker `:latest`; local Docker runs and the VS Code **Lint** tasks track `:latest`. Each takes the file globs directly, for example `docker run --rm -v "$PWD":/work -w /work ghcr.io/streetsidesoftware/cspell README.md HISTORY.md` or `... davidanson/markdownlint-cli2 '**/*.md'`. The cspell accepted-word list and the path exclusions both live in [`cspell.json`](./cspell.json), the single source: the Code Spell Checker extension reads `cspell.json` ahead of the workspace `cSpell` settings (so GUI "Add to dictionary" lands words there), and the CLI and CI read the same file. Do not keep a parallel word list in the `.code-workspace` file. A local cspell or markdownlint result that reports zero files checked scanned nothing; ignore it. There is intentionally no wrapper script; the editor, these Docker images, and CI are the supported runners. - **Release notes.** Keep a short summary in [`README.md`](./README.md) and the full history in [`HISTORY.md`](./HISTORY.md); update both when cutting a release. ## Workflow YAML Conventions diff --git a/Directory.Packages.props b/Directory.Packages.props index de12f18..fdfbc51 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -9,8 +9,8 @@ - + diff --git a/UtilitiesTests/.editorconfig b/UtilitiesTests/.editorconfig index f443e5e..1bb70bb 100644 --- a/UtilitiesTests/.editorconfig +++ b/UtilitiesTests/.editorconfig @@ -8,6 +8,3 @@ dotnet_diagnostic.CA1707.severity = none # CA1515: xUnit discovers only public test classes, so they cannot be internal. dotnet_diagnostic.CA1515.severity = none - -# CA2007: xUnit forbids ConfigureAwait in test methods (xUnit1030), so CA2007 cannot be satisfied in test code. -dotnet_diagnostic.CA2007.severity = none diff --git a/UtilitiesTests/UtilitiesTests.csproj b/UtilitiesTests/UtilitiesTests.csproj index ab15043..6d87d47 100644 --- a/UtilitiesTests/UtilitiesTests.csproj +++ b/UtilitiesTests/UtilitiesTests.csproj @@ -1,28 +1,12 @@ - false - Pieter Viljoen - Pieter Viljoen - Pieter Viljoen - Generally useful utility classes - 1.1.0.1 - 1.1.0.1 - 1.1.0.0 - ptr727.Utilities.Tests - UtilitiesTests + true ptr727.Utilities.Tests - en - true - true - true - snupkg - - - + all runtime; build; native; contentfiles; analyzers; buildtransitive