Skip to content

Commit fd7890b

Browse files
authored
feat: add reusable spellcheck workflow (ipdxco#119)
* feat: added spellcheck workflow for checking spelling * chore: remove unnecessary permissions from spellcheck * chore: ignore .mod and .sum files in spellcheck * chore: show rendered .cspell.json * chore: trim spellcheck env vars * chore: report on typos only * chore: ignore adin and botto * fix: do not move .cspell.json * chore: update ignored words list * chore: update list of ignored words in spellcheck * chore: add helper cspell fix script * chore: update cspell yaml config paths * fix: env substitution in spellcheck * chore: fix yaml to json conversion * fix: the spellcheck fixer script * chore: update the cspell version * chore: release v1.0.28
1 parent 5306ba7 commit fd7890b

File tree

4 files changed

+193
-0
lines changed

4 files changed

+193
-0
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
name: Check Spelling
2+
3+
on:
4+
workflow_call:
5+
6+
jobs:
7+
spellcheck:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/checkout@v4
11+
12+
- name: Extend the GitHub context
13+
id: github
14+
env:
15+
BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }}
16+
run: |
17+
if [[ -n "$BASE_SHA" ]]; then
18+
echo "base_sha=$BASE_SHA" | tee -a $GITHUB_OUTPUT
19+
git fetch origin "$BASE_SHA"
20+
git diff --name-only "$BASE_SHA" |
21+
jq -Rnc '[inputs]' |
22+
xargs -I {} -0 echo "changed_files={}" |
23+
tee -a $GITHUB_OUTPUT
24+
fi
25+
26+
- id: config
27+
uses: actions/github-script@v7
28+
with:
29+
script: |
30+
const fs = require("fs");
31+
32+
const jsonConfigPaths = [
33+
".cspell.json",
34+
"cspell.json",
35+
"cspell.config.json",
36+
];
37+
const yamlConfigPaths = [
38+
".cspell.yaml",
39+
".cspell.yml",
40+
"cspell.yaml",
41+
"cspell.yml",
42+
"cspell.config.yaml",
43+
"cspell.config.yml",
44+
];
45+
46+
for (const configPath of jsonConfigPaths) {
47+
if (fs.existsSync(configPath)) {
48+
console.log(`Found config file at ${configPath}`);
49+
core.setOutput("path", configPath);
50+
core.setOutput("type", "json");
51+
return;
52+
}
53+
}
54+
55+
for (const configPath of yamlConfigPaths) {
56+
if (fs.existsSync(configPath)) {
57+
console.log(`Found config file at ${configPath}`);
58+
core.setOutput("path", configPath);
59+
core.setOutput("type", "yaml");
60+
return;
61+
}
62+
}
63+
64+
- if: steps.config.outputs.path == ''
65+
run: echo '{}' > '.cspell.json'
66+
67+
- if: steps.config.outputs.type == 'json' && steps.config.outputs.path != '.cspell.json'
68+
env:
69+
CONFIG_PATH: ${{ steps.config.outputs.path }}
70+
run: mv "$CONFIG_PATH" '.cspell.json'
71+
72+
- if: steps.config.outputs.type == 'yaml'
73+
env:
74+
CONFIG_PATH: ${{ steps.config.outputs.path }}
75+
run: |
76+
yq -o=json '.' "$CONFIG_PATH" > '.cspell.json'
77+
rm "$CONFIG_PATH"
78+
79+
- uses: actions/github-script@v7
80+
env:
81+
IGNORE_WORDS: |
82+
Adin
83+
IGNORE_PATHS: |
84+
**/*.mod
85+
**/*.sum
86+
with:
87+
script: |
88+
const fs = require("fs");
89+
90+
const config = JSON.parse(fs.readFileSync(".cspell.json"));
91+
92+
config.ignoreWords = config.ignoreWords ?? [];
93+
for (const word of process.env.IGNORE_WORDS.trim().split("\n")) {
94+
config.ignoreWords.push(word);
95+
}
96+
97+
config.ignorePaths = config.ignorePaths ?? [];
98+
for (const path of process.env.IGNORE_PATHS.trim().split("\n")) {
99+
config.ignorePaths.push(path);
100+
}
101+
102+
fs.writeFileSync(".cspell.json", JSON.stringify(config, null, 2));
103+
104+
- run: jq . .cspell.json
105+
106+
- uses: streetsidesoftware/cspell-action@157048954070986ce4315d0813573a2d8faee361 # v7.1.1
107+
with:
108+
incremental_files_only: ${{
109+
steps.github.outputs.base_sha && !(
110+
contains(fromJSON(steps.github.outputs.changed_files), '.github/workflows/spellcheck.yml') ||
111+
(
112+
steps.config.outputs.path != '' &&
113+
contains(fromJSON(steps.github.outputs.changed_files), steps.config.outputs.path)
114+
)
115+
) && 'true' || 'false'
116+
}}
117+
config: '.cspell.json'
118+
report: typos

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## Unreleased
88

9+
## [1.0.28] - 2025-07-16
10+
### Added
11+
- new `spellcheck` workflow template that uses `cspell` to check spelling
12+
913
## [1.0.27] - 2025-06-15
1014
### Fixed
1115
- fixed the latest version check in the `releaser` workflow

scripts/cspell-fix.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#!/usr/bin/env node
2+
3+
const { readFileSync, writeFileSync } = require('fs');
4+
const { execSync } = require('child_process');
5+
const { fileURLToPath } = require('url');
6+
7+
const stdout = execSync('cspell lint --reporter @cspell/cspell-json-reporter --report typos --no-exit-code .');
8+
9+
const { issues } = JSON.parse(stdout.toString());
10+
11+
const seen = new Map();
12+
13+
for (const issue of issues) {
14+
if (!issue.hasSimpleSuggestions || !issue.hasPreferredSuggestions) {
15+
console.debug(`Issue ${issue.text} has no simple, preferred suggestions`);
16+
continue;
17+
}
18+
19+
const filePath = fileURLToPath(issue.uri);
20+
const text = issue.text;
21+
22+
if (!seen.has(filePath)) {
23+
seen.set(filePath, new Set());
24+
}
25+
26+
if (seen.get(filePath).has(text)) {
27+
console.debug(`Skipping ${text} in ${filePath}`);
28+
continue;
29+
}
30+
31+
seen.get(filePath).add(text);
32+
33+
let suggestion;
34+
for (const s of issue.suggestionsEx) {
35+
if (s.isPreferred) {
36+
suggestion = s;
37+
break;
38+
}
39+
}
40+
41+
if (suggestion === undefined) {
42+
console.warn(`No preferred suggestion for ${issue.text}`);
43+
continue;
44+
}
45+
46+
const word = suggestion.wordAdjustedToMatchCase ?? suggestion.word;
47+
48+
const content = readFileSync(filePath, 'utf8');
49+
writeFileSync(filePath, content.replaceAll(text, word));
50+
51+
console.debug(`Replaced ${text} with ${word} in ${filePath}`);
52+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: Spellcheck
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches: ${{{ .github.protected_branches + [.github.default_branch] | unique }}}
7+
workflow_dispatch:
8+
merge_group:
9+
10+
permissions:
11+
contents: read
12+
13+
concurrency:
14+
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }}
15+
cancel-in-progress: true
16+
17+
jobs:
18+
go-check:
19+
uses: ipdxco/unified-github-workflows/.github/workflows/reusable-spellcheck.yml@${{{ .config.versions.uci // (.source.tag | sub("\\.[^\\.]+\\.[^\\.\\-\\+]+(?=\\-|\\+|$)"; "")) }}}

0 commit comments

Comments
 (0)