Skip to content

Commit cda7309

Browse files
author
endolinbot
committed
chore(shellcheck): add yarn shellcheck script and CI workflow
Adds a deterministic lint gate over every tracked .sh file in the repository. - `scripts/shellcheck.sh` enumerates `git ls-files '*.sh'` and runs `shellcheck -S warning` over the list, forwarding any extra args to the underlying checker. Exits 0 when the list is empty so forks or branches that have not yet adopted a shell script stay green. - `yarn shellcheck` wires the wrapper into the root `package.json` scripts table. - `.github/workflows/shellcheck.yml` runs the gate on push to master and on any pull_request that touches a `.sh` file (the workflow's `paths:` filter). A PR that touches no shell scripts does not trigger the workflow at all, matching the maintainer's "skip when no .sh in the diff from the base" requirement. shellcheck ships preinstalled on `ubuntu-latest` runners so no additional dependency or apt install is needed. Action pins follow the project's existing zizmor-pedantic posture (`actions/checkout@de0fac2e...`); the workflow scope grants `contents: read` and the job runs with `persist-credentials: false`.
1 parent 42c39b0 commit cda7309

3 files changed

Lines changed: 78 additions & 0 deletions

File tree

.github/workflows/shellcheck.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Shell script lint
2+
3+
# Run shellcheck against every .sh file tracked in the repo. The
4+
# workflow is gated on path-filter `**/*.sh`, so a PR that touches no
5+
# shell scripts does not trigger any runs at all (the "skip when no
6+
# .sh in the diff from the base" behavior).
7+
#
8+
# Pushes to master always run (no path-filter), so the gate is
9+
# authoritative for the master branch.
10+
11+
on:
12+
push:
13+
branches: [master]
14+
pull_request:
15+
paths:
16+
- '**/*.sh'
17+
- 'scripts/shellcheck.sh'
18+
- '.github/workflows/shellcheck.yml'
19+
20+
permissions:
21+
contents: read
22+
23+
concurrency:
24+
group: ${{ github.workflow }}-${{ github.ref }}
25+
cancel-in-progress: true
26+
27+
jobs:
28+
shellcheck:
29+
name: shellcheck
30+
runs-on: ubuntu-latest
31+
steps:
32+
- name: Checkout
33+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
34+
with:
35+
persist-credentials: false
36+
37+
# shellcheck ships preinstalled on ubuntu-latest runners. Print
38+
# the version so a regression in the image surfaces here rather
39+
# than as an unexplained gate flap.
40+
- name: Show shellcheck version
41+
run: shellcheck --version
42+
43+
- name: Run yarn shellcheck
44+
run: ./scripts/shellcheck.sh

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
"lint:fix": "yarn lint:eslint -- --fix",
5656
"lint:workspaces:fix": "yarn workspaces foreach --all run lint-fix",
5757
"lint:prettier": "prettier --check .github packages",
58+
"shellcheck": "scripts/shellcheck.sh",
5859
"release:npm": "scripts/release-npm.mjs",
5960
"pack:all": "scripts/pack-all.mjs",
6061
"smoketest:publish": "scripts/smoketest-publishing.sh",

scripts/shellcheck.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/bin/sh
2+
# Run shellcheck against every .sh file tracked in the repository.
3+
#
4+
# Exits 0 when no .sh files are tracked. Extra arguments are forwarded to
5+
# the underlying checker, so callers can override severity or exclude
6+
# codes:
7+
#
8+
# yarn shellcheck # default severity warning
9+
# yarn shellcheck --severity=error # tighter gate
10+
# yarn shellcheck -- -e SC2086 # exclude a code
11+
#
12+
# The list is enumerated via `git ls-files '*.sh'` so untracked scratch
13+
# scripts and worktree noise are ignored.
14+
15+
set -eu
16+
17+
# Read NUL-delimited paths into a single newline-separated list so the body
18+
# can branch on emptiness. xargs is not used directly because BSD xargs
19+
# (macOS) lacks `-r` and runs the command on an empty list, which would
20+
# invoke `shellcheck` with no positional arguments and read from stdin.
21+
files=$(git ls-files -z '*.sh' | tr '\0' '\n')
22+
23+
if [ -z "$files" ]; then
24+
echo "shellcheck: no .sh files tracked; skipping."
25+
exit 0
26+
fi
27+
28+
# shellcheck disable=SC2086
29+
# Word splitting on $files is intentional: each line is a separate path
30+
# and tracked .sh filenames in this repo do not contain whitespace.
31+
# `git ls-files` would happily emit NULs for whitespace-bearing names; if
32+
# such a name lands here, switch to xargs -0 with a portability shim.
33+
echo "$files" | xargs shellcheck -S warning "$@"

0 commit comments

Comments
 (0)