diff --git a/.cspell.json b/.cspell.json index a85cf42..e121401 100644 --- a/.cspell.json +++ b/.cspell.json @@ -1,7 +1,7 @@ { "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json", "version": "0.2", - "words": ["Bitwarden"], + "unknownWords": "report-common-typos", "flagWords": [], "ignorePaths": [ ".vscode", diff --git a/.gitconfig b/.gitconfig index 06fd62b..7bc3a67 100644 --- a/.gitconfig +++ b/.gitconfig @@ -1,3 +1,3 @@ [hook "linter"] event = pre-commit - command = echo "Add linter in ./gitconfig" + command = sh .githooks/pre-commit diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 0000000..b2f59a2 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,29 @@ +#!/usr/bin/env sh +# +# Pre-commit linter: formats and spell-checks staged files. +# - Prettier (--check) on staged Markdown, JSON, JSON5, and YAML +# - CSpell on staged Markdown +# +# Wired up through .gitconfig ([hook "linter"]). Enable it once per clone by +# running the following from the repo root: +# +# git config set --local include.path "../.gitconfig" +# +# Requires Node.js (>=18); the tools are fetched on demand via `npx --yes`. + +set -eu + +staged_files=$(git diff --cached --name-only --diff-filter=ACMR -- '*.md' '*.json' '*.json5' '*.yml' '*.yaml') + +if [ -n "$staged_files" ]; then + # Word-splitting is intentional: pass each newline-separated path as an argument. + # shellcheck disable=SC2086 + npx --yes prettier@3.9.1 --check $staged_files +fi + +staged_md=$(git diff --cached --name-only --diff-filter=ACMR -- '*.md') + +if [ -n "$staged_md" ]; then + # shellcheck disable=SC2086 + npx --yes cspell@10.0.1 --no-progress --gitignore $staged_md +fi diff --git a/.github/renovate.json b/.github/renovate.json index 341c264..8697d38 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,8 +1,35 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": ["github>bitwarden/renovate-config"], - "enabledManagers": ["cargo", "docker-compose", "dockerfile", "github-actions", "npm", "nuget"], + "enabledManagers": [ + "cargo", + "custom.regex", + "docker-compose", + "dockerfile", + "github-actions", + "npm", + "nuget" + ], + "customManagers": [ + { + "customType": "regex", + "description": "Pinned npx tool versions in the lint workflow and git hooks", + "fileMatch": [ + "^\\.github/workflows/lint\\.yml$", + "^\\.githooks/pre-commit$" + ], + "matchStrings": [ + "(?prettier|cspell)@(?\\d+\\.\\d+\\.\\d+)" + ], + "datasourceTemplate": "npm" + } + ], "packageRules": [ + { + "groupName": "lint tooling", + "matchManagers": ["custom.regex"], + "matchPackageNames": ["prettier", "cspell"] + }, { "groupName": "cargo minor", "matchManagers": ["cargo"], diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..55255c0 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,50 @@ +name: Lint + +# Keep the Prettier and CSpell tooling here in sync with the pre-commit linter +# in .githooks/pre-commit (versions, file globs, and flags) so local commits and +# CI enforce the same rules. Renovate bumps both together via .github/renovate.json. + +on: + workflow_dispatch: + push: + branches: [main] + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: read + +jobs: + format: + name: Prettier + runs-on: ubuntu-24.04 + steps: + - name: Check out repo + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: Set up Node + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: 24 + + - name: Check formatting + run: npx --yes prettier@3.9.1 --check "**/*.{md,json,json5,yml,yaml}" + + spell: + name: CSpell + runs-on: ubuntu-24.04 + steps: + - name: Check out repo + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: Set up Node + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: 24 + + - name: Check spelling + run: npx --yes cspell@10.0.1 --no-progress --gitignore "**/*.md" diff --git a/README.md b/README.md index 2c88469..99e2578 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,26 @@ This repository serves as a template for others and establishes very basic struc ## Hooks -Hooks are centrally configured for the repo in the `.gitconfig` file. +Hooks are centrally configured for the repo in the `.gitconfig` file. The `pre-commit` hook +([`.githooks/pre-commit`](.githooks/pre-commit)) runs [Prettier](https://prettier.io) (`--check`) on +staged Markdown, JSON, JSON5, and YAML, and [CSpell](https://cspell.org) against staged Markdown to +catch common typos; the spell-checker's settings live in `.cspell.json`. The same checks run in CI on +every pull request via the [Lint workflow](.github/workflows/lint.yml), and the pinned tool versions — +in both the hook and the workflow — are kept current by Renovate. -If you configure a linter you will want to include docs to have contributors run the following -command: +Hooks are opt-in per clone. Enable them once, from the repo root: ```bash git config set --local include.path "../.gitconfig" ``` + +Running the hook requires [Node.js](https://nodejs.org) (>=18); the tools are fetched on demand via +`npx`. + +## Customizing the linter + +Because this is a template, treat the linter as a starting point and adjust it for your repo. The file +extensions are the most likely thing to change: Prettier checks Markdown, JSON, JSON5, and YAML, and +CSpell checks Markdown. If you change those globs, update both +[`.githooks/pre-commit`](.githooks/pre-commit) and the [Lint workflow](.github/workflows/lint.yml) so +local commits and CI stay in sync. Swapping tools or changing the pinned versions works the same way.