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
28 changes: 28 additions & 0 deletions .github/scripts/qc-actionlint-setup.sh
Original file line number Diff line number Diff line change
@@ -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
22 changes: 22 additions & 0 deletions .github/scripts/qc-filter-changed-paths.sh
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion .github/workflows/accessibility-checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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: >
Expand Down
23 changes: 11 additions & 12 deletions .github/workflows/quality-checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 }}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test-workflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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 || '' }}
Expand All @@ -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 || '' }}
Expand Down
54 changes: 28 additions & 26 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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 <files>` |
| `*.html` | axe via `lint-changed.sh` (optional locally) or CI Suite 2 |
| Workflow inputs / README tables | Keep **README.md** and workflow `inputs` in sync |
| 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` (`shfmt` + `shellcheck -x` on all scripts) |
| `*.html` | axe via `lint-changed.sh` (optional locally) or CI Accessibility Audits |
| Workflow inputs / README tables | Keep **README.md** and workflow `inputs` in sync |

### Suite mapping (CI vs local)
### Workflow mapping (CI vs local)

| Suite | CI workflow | Local equivalent |
| --------------------- | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| **1 — Linters** | `test-workflow` → `quality-checks.yaml` | `npm run lint` (includes `lint:docs`) |
| **2 — Accessibility** | `test-workflow` → `accessibility-checks.yaml` | axe on changed `.html` via `lint-changed.sh`; Lighthouse needs deployed `urls` (CI only unless you pass URLs locally) |
| Workflow | CI workflow | Local equivalent |
| ------------------------ | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| **Linters** | `test-workflow` → `quality-checks.yaml` | `npm run lint` (includes `lint:docs`) |
| **Accessibility Audits** | `test-workflow` → `accessibility-checks.yaml` | axe on changed `.html` via `lint-changed.sh`; Lighthouse needs deployed `urls` (CI only unless you pass URLs locally) |

### Tool install (if a script reports “skipped”)

| Tool | Install |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| **actionlint** | `brew install actionlint` |
| **actionlint** | `brew install actionlint` (CI uses `.github/scripts/qc-actionlint-setup.sh`, pinned `1.7.12`) |
| **yamllint** | `pip install yamllint` |
| **shfmt** | `brew install shfmt` |
| **shellcheck** | `brew install shellcheck` |
Expand All @@ -119,6 +119,8 @@ LINT_BASE=origin/main ./scripts/lint-changed.sh
### Checklist before handoff

- [ ] **`npm run fix:docs`** exits 0 (or `npm run lint:docs` if you did not need to write)
- [ ] **`npm run lint:shell`** exits 0 when you changed `.github/scripts/*.sh` or `scripts/*.sh` (use
`shellcheck -x` so sourced helpers are analyzed)
- [ ] **`npm run lint`** or **`./scripts/lint-changed.sh`** exits 0 when you changed workflows, shell, or config
- [ ] If workflows or inputs changed, README tables updated
- [ ] New third-party actions use full commit SHAs
Expand Down
9 changes: 5 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,19 @@ npm run fix:docs
npm run lint:changed
```

`fix:docs` formats and lints **all** Markdown (required on every PR). For a full Suite 1 pass:
`fix:docs` formats and lints **all** Markdown (required on every PR). For a full Linters pass:

```bash
npm run lint
```

Install optional tools listed in **AGENTS.md** when `lint-changed` reports a skip.
**`npm run lint`** mirrors CI **Suite 1 — Linters**; Suite 2 (accessibility) runs in
CI via `test-workflow.yaml`.
**`npm run lint`** mirrors CI **Linters**; **Accessibility Audits** run in CI via
`test-workflow.yaml`.

Shell script changes require **shfmt** and **shellcheck** (`brew install shfmt shellcheck`,
or `npm run lint:shell` after installing shfmt).
or `npm run lint:shell` after installing both). Use **`shellcheck -x`** so sourced files under
`.github/scripts/` are checked.

Documentation-only changes still need **Prettier** and **Markdownlint** on touched
Markdown files.
Loading
Loading