Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/validate-task.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
7 changes: 6 additions & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -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
57 changes: 57 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": []
}
]
}
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
<PackageVersion Include="Serilog" Version="4.4.0" />
<PackageVersion Include="Serilog.Extensions.Logging" Version="10.0.0" />
<PackageVersion Include="Serilog.Sinks.Console" Version="6.1.1" />
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.analyzers" Version="1.27.0" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
<PackageVersion Include="xunit.v3" Version="3.2.2" />
</ItemGroup>
</Project>
3 changes: 0 additions & 3 deletions UtilitiesTests/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
20 changes: 2 additions & 18 deletions UtilitiesTests/UtilitiesTests.csproj
Original file line number Diff line number Diff line change
@@ -1,28 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Authors>Pieter Viljoen</Authors>
<Company>Pieter Viljoen</Company>
<Copyright>Pieter Viljoen</Copyright>
<Description>Generally useful utility classes</Description>
<Version>1.1.0.1</Version>
<FileVersion>1.1.0.1</FileVersion>
<AssemblyVersion>1.1.0.0</AssemblyVersion>
<PackageId>ptr727.Utilities.Tests</PackageId>
<AssemblyName>UtilitiesTests</AssemblyName>
<IsTestProject>true</IsTestProject>
<RootNamespace>ptr727.Utilities.Tests</RootNamespace>
<NeutralLanguage>en</NeutralLanguage>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AwesomeAssertions" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.v3" />
<PackageReference Include="xunit.analyzers">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down