Skip to content

Commit 26af0b3

Browse files
committed
Add workflow linting with actionlint
1 parent 363bcf6 commit 26af0b3

File tree

6 files changed

+76
-0
lines changed

6 files changed

+76
-0
lines changed

.github/workflows/template-ci.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,26 @@ permissions:
1010
contents: read
1111

1212
jobs:
13+
workflow-lint:
14+
name: Workflow Lint
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v4
19+
20+
- name: Setup Node
21+
uses: actions/setup-node@v4
22+
with:
23+
node-version-file: .nvmrc
24+
25+
- name: Setup Go
26+
uses: actions/setup-go@v5
27+
with:
28+
go-version: "1.25.1"
29+
30+
- name: Lint GitHub Actions workflows
31+
run: npm run check:workflows
32+
1333
contract-drift:
1434
name: Contract Drift
1535
runs-on: ubuntu-latest

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ Use these commands before finishing work:
4949

5050
```bash
5151
npm run check:contract
52+
npm run check:workflows
5253
npm run check
5354
```
5455

CONTRIBUTING.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ If Docker is available locally, you can also verify the production-style images:
6969
npm run check:images
7070
```
7171

72+
If Go is available locally, you can also lint GitHub Actions workflows:
73+
74+
```bash
75+
npm run check:workflows
76+
```
77+
7278
## Changing the API Contract
7379

7480
If you modify request or response shapes:

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ npm run dev:down
9696
npm run api:types
9797
npm run check:contract
9898
npm run check:images
99+
npm run check:workflows
99100
npm run check
100101
```
101102

@@ -112,6 +113,8 @@ The root check runs:
112113

113114
`check:images` is separate and intended for environments where a Docker daemon is available.
114115

116+
`check:workflows` lints `.github/workflows/` with a pinned `actionlint` version via Go.
117+
115118
## Releases
116119

117120
- Release Drafter keeps a draft release updated from merged pull requests on `main` and can auto-label incoming pull requests by path.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"check:contract": "node scripts/check-contract-drift.mjs",
1010
"check:images": "node scripts/check-docker-builds.mjs",
1111
"check:release-smoke": "node scripts/check-release-smoke.mjs",
12+
"check:workflows": "node scripts/check-actionlint.mjs",
1213
"check": "node scripts/check.mjs"
1314
},
1415
"keywords": [

scripts/check-actionlint.mjs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { spawnSync } from "node:child_process";
2+
import process from "node:process";
3+
4+
const ACTIONLINT_VERSION = process.env.ACTIONLINT_VERSION ?? "v1.7.11";
5+
const shell = process.platform === "win32";
6+
7+
function run(command, args, options = {}) {
8+
return spawnSync(command, args, {
9+
stdio: options.capture ? "pipe" : "inherit",
10+
encoding: options.capture ? "utf8" : undefined,
11+
shell,
12+
});
13+
}
14+
15+
const goVersion = run("go", ["version"], { capture: true });
16+
17+
if (goVersion.error || goVersion.status !== 0) {
18+
const details = [goVersion.stdout, goVersion.stderr].filter(Boolean).join("\n").trim();
19+
console.error(
20+
"Go is required to run workflow lint locally. Install Go or rely on the CI workflow-lint job.",
21+
);
22+
23+
if (details) {
24+
console.error(details);
25+
}
26+
27+
process.exit(goVersion.status ?? 1);
28+
}
29+
30+
const args = [
31+
"run",
32+
`github.com/rhysd/actionlint/cmd/actionlint@${ACTIONLINT_VERSION}`,
33+
"-shellcheck=",
34+
"-pyflakes=",
35+
...process.argv.slice(2),
36+
];
37+
38+
const result = run("go", args);
39+
40+
if (result.error) {
41+
console.error(result.error.message);
42+
process.exit(1);
43+
}
44+
45+
process.exit(result.status ?? 1);

0 commit comments

Comments
 (0)