diff --git a/.github/scripts/qc-actionlint-setup.sh b/.github/scripts/qc-actionlint-setup.sh
new file mode 100755
index 0000000..f42d39b
--- /dev/null
+++ b/.github/scripts/qc-actionlint-setup.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+# Install a pinned actionlint binary via the upstream download script.
+# Sets ACTIONLINT_BIN and prepends the install dir to PATH (GitHub Actions).
+set -euo pipefail
+
+ACTIONLINT_VERSION="${ACTIONLINT_VERSION:-1.7.12}"
+install_dir="${ACTIONLINT_INSTALL_DIR:-${RUNNER_TEMP:-/tmp}/actionlint}"
+
+mkdir -p "${install_dir}"
+script_url="https://raw.githubusercontent.com/rhysd/actionlint/v${ACTIONLINT_VERSION}/scripts/download-actionlint.bash"
+bash <(curl -fsSL "${script_url}") "${ACTIONLINT_VERSION}" "${install_dir}"
+
+ACTIONLINT_BIN="${install_dir}/actionlint"
+export ACTIONLINT_BIN
+
+if [[ -n "${GITHUB_PATH:-}" ]]; then
+ echo "${install_dir}" >>"${GITHUB_PATH}"
+fi
+
+if [[ -n "${GITHUB_ENV:-}" ]]; then
+ echo "ACTIONLINT_BIN=${ACTIONLINT_BIN}" >>"${GITHUB_ENV}"
+fi
+
+if [[ -n "${GITHUB_OUTPUT:-}" ]]; then
+ echo "executable=${ACTIONLINT_BIN}" >>"${GITHUB_OUTPUT}"
+fi
+
+"${ACTIONLINT_BIN}" -version
diff --git a/.github/scripts/qc-filter-changed-paths.sh b/.github/scripts/qc-filter-changed-paths.sh
new file mode 100755
index 0000000..5bea073
--- /dev/null
+++ b/.github/scripts/qc-filter-changed-paths.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+# Drop dependency and build-output paths from PR-scoped changed-file lists.
+# Reads paths from stdin; prints kept paths to stdout.
+set -euo pipefail
+
+qc_should_skip_changed_path() {
+ local path="$1"
+ case "${path}" in
+ node_modules/* | */node_modules/*) return 0 ;;
+ vendor/* | */vendor/*) return 0 ;;
+ dist/* | */dist/*) return 0 ;;
+ build/* | */build/*) return 0 ;;
+ coverage/* | */coverage/*) return 0 ;;
+ esac
+ return 1
+}
+
+while IFS= read -r path || [[ -n "${path}" ]]; do
+ [[ -z "${path}" ]] && continue
+ qc_should_skip_changed_path "${path}" && continue
+ printf '%s\n' "${path}"
+done
diff --git a/.github/workflows/accessibility-checks.yaml b/.github/workflows/accessibility-checks.yaml
index 7edf591..58299fd 100644
--- a/.github/workflows/accessibility-checks.yaml
+++ b/.github/workflows/accessibility-checks.yaml
@@ -22,7 +22,7 @@ on:
node_version:
description: Node.js version for axe-core and Lighthouse CI tooling.
required: false
- default: '20'
+ default: '24'
type: string
axe_run:
description: >
diff --git a/.github/workflows/quality-checks.yaml b/.github/workflows/quality-checks.yaml
index 30d2dbe..003a362 100644
--- a/.github/workflows/quality-checks.yaml
+++ b/.github/workflows/quality-checks.yaml
@@ -24,7 +24,7 @@ on:
Node.js version for ESLint, markdownlint-cli2, Prettier, and
accessibility-related installs in sibling workflows.
required: false
- default: '20'
+ default: '24'
type: string
go_version:
description: Go toolchain version for golangci-lint.
@@ -169,17 +169,14 @@ jobs:
fetch-depth: 0
- name: 'Install actionlint'
+ id: actionlint-install
env:
# Pin release; bump intentionally when upgrading.
- ACTIONLINT_VERSION: v1.7.7
+ ACTIONLINT_VERSION: '1.7.12'
run: |
set -euo pipefail
- tag="${ACTIONLINT_VERSION#v}"
- url="https://github.com/rhysd/actionlint/releases/download/${ACTIONLINT_VERSION}/actionlint_${tag}_linux_amd64.tar.gz"
- curl -fsSL "$url" -o actionlint.tar.gz
- tar -xzf actionlint.tar.gz actionlint
- sudo mv actionlint /usr/local/bin/
- rm actionlint.tar.gz
+ # shellcheck source=.github/scripts/qc-actionlint-setup.sh
+ source .github/scripts/qc-actionlint-setup.sh
- name: 'Get changed GitHub Actions files'
id: changed-files
@@ -235,7 +232,7 @@ jobs:
echo 'No existing paths to lint'
exit 0
fi
- actionlint "${paths[@]}"
+ "${ACTIONLINT_BIN:-actionlint}" "${paths[@]}"
eslint:
if: ${{ inputs.eslint_run == true }}
@@ -494,7 +491,8 @@ jobs:
fi
mapfile -t CHANGED_FILES < <(
git diff --name-only --diff-filter=ACMR "${BASE_REF}"...HEAD |
- grep -E '\.(md|markdown)$' || true
+ grep -E '\.(md|markdown)$' |
+ .github/scripts/qc-filter-changed-paths.sh || true
)
if [[ ${#CHANGED_FILES[@]} -gt 0 ]] && \
[[ -n "${CHANGED_FILES[0]}" ]]; then
@@ -571,7 +569,8 @@ jobs:
mapfile -t CHANGED_FILES < <(
git diff --name-only --diff-filter=ACMR "${BASE_REF}"...HEAD |
grep -E \
- '\.(js|jsx|ts|tsx|json|css|scss|md|markdown)$' || true
+ '\.(js|jsx|ts|tsx|json|css|scss|md|markdown)$' |
+ .github/scripts/qc-filter-changed-paths.sh || true
)
if [[ ${#CHANGED_FILES[@]} -gt 0 ]] && \
[[ -n "${CHANGED_FILES[0]}" ]]; then
@@ -747,7 +746,7 @@ jobs:
echo 'No existing paths to lint'
exit 0
fi
- shellcheck "${paths[@]}"
+ shellcheck -x "${paths[@]}"
stylua:
if: ${{ inputs.stylua_run == true }}
diff --git a/.github/workflows/test-workflow.yaml b/.github/workflows/test-workflow.yaml
index 2a60bd1..2e523bd 100644
--- a/.github/workflows/test-workflow.yaml
+++ b/.github/workflows/test-workflow.yaml
@@ -8,7 +8,7 @@ on:
jobs:
linters:
- name: 'Suite 1 — Linters'
+ name: 'Linters'
uses: ./.github/workflows/quality-checks.yaml
with:
diff_base: ${{ github.event.pull_request.base.sha || '' }}
@@ -29,7 +29,7 @@ jobs:
secrets: inherit
accessibility:
- name: 'Suite 2 — Accessibility'
+ name: 'Accessibility Audits'
uses: ./.github/workflows/accessibility-checks.yaml
with:
diff_base: ${{ github.event.pull_request.base.sha || '' }}
diff --git a/AGENTS.md b/AGENTS.md
index ba53dbb..fe894c5 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -1,20 +1,20 @@
# Agent guide — quality-checks
-Reusable GitHub Actions for **Suite 1 (linters)** and **Suite 2 (accessibility)** on
-pull-request diffs. Keep workflows **opt-in**, **PR-scoped**, and **pinned to commit
-SHAs** for third-party actions.
+Reusable GitHub Actions for **Linters** and **Accessibility Audits** on pull-request
+diffs. Keep workflows **opt-in**, **PR-scoped**, and **pinned to commit SHAs** for
+third-party actions.
## Repository layout
-| Path | Purpose |
-| --------------------------------------------- | -------------------------------------------- |
-| `.github/workflows/quality-checks.yaml` | Reusable linter workflow (Suite 1) |
-| `.github/workflows/accessibility-checks.yaml` | Reusable axe + Lighthouse workflow (Suite 2) |
-| `.github/workflows/test-workflow.yaml` | Self-test on PRs (both suites) |
-| `.github/scripts/qc-resolve-base.sh` | Shared diff-base resolution for jobs |
-| `scripts/lint-changed.sh` | Run local linters matching changed files |
-| `docs/assets/` | Branding (logo SVG) |
-| `docs/fixtures/a11y-sample.html` | axe self-test fixture |
+| Path | Purpose |
+| --------------------------------------------- | ---------------------------------------- |
+| `.github/workflows/quality-checks.yaml` | Reusable linter workflow |
+| `.github/workflows/accessibility-checks.yaml` | Reusable axe + Lighthouse workflow |
+| `.github/workflows/test-workflow.yaml` | Self-test on PRs (both workflows) |
+| `.github/scripts/qc-resolve-base.sh` | Shared diff-base resolution for jobs |
+| `scripts/lint-changed.sh` | Run local linters matching changed files |
+| `docs/assets/` | Branding (logo SVG) |
+| `docs/fixtures/a11y-sample.html` | axe self-test fixture |
## Workflow conventions
@@ -73,7 +73,7 @@ npm run lint:docs
./scripts/lint-changed.sh
```
-Or the full Suite 1 pass:
+Or the full Linters pass:
```bash
npm run lint
@@ -89,26 +89,26 @@ LINT_BASE=origin/main ./scripts/lint-changed.sh
### If you edited … also run …
-| Paths you changed | Additional checks |
-| ---------------------------------------------------------------------------------- | ---------------------------------------------------------- |
-| `.github/workflows/*.yaml`, `test-workflow.yaml` | `npm run lint:yaml`, `npm run lint:workflows` |
-| `.github/ISSUE_TEMPLATE/**`, `dependabot.yaml`, `.yamllint`, `.markdownlint*.yaml` | `npm run lint:yaml` |
-| `.github/scripts/*.sh`, `scripts/*.sh` | `npm run lint:shell`, `shellcheck
- Suite 1 runs opt-in linters only on changed files. Suite 2 runs axe-core and - Lighthouse CI against deployed URLs and/or local HTML — tuned for fast, - actionable feedback in pull requests. + Linters run opt-in checks only on changed files. Accessibility Audits run + axe-core and Lighthouse CI against deployed URLs and/or local HTML — tuned + for fast, actionable feedback in pull requests.
@@ -30,12 +30,12 @@
alt="PR-scoped checks"
/>