Skip to content

Commit fae312f

Browse files
committed
MAJOR: add aspell as additional check for spelling errors
1 parent f74106a commit fae312f

File tree

12 files changed

+244
-91
lines changed

12 files changed

+244
-91
lines changed

.aspell.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
mode: subject
2+
allowed:
3+
- aspell

.github/workflows/actions.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@ jobs:
66
runs-on: ubuntu-latest
77
steps:
88
- uses: actions/checkout@v4
9+
- name: Set up Go
10+
uses: actions/setup-go@v4
11+
with:
12+
go-version-file: 'go.mod'
13+
check-latest: true
914
- name: golangci-lint
10-
uses: golangci/golangci-lint-action@v3
15+
uses: golangci/golangci-lint-action@v6
1116
go_build:
1217
name: Go build
1318
runs-on: ubuntu-latest
@@ -32,6 +37,8 @@ jobs:
3237
runs-on: ubuntu-latest
3338
needs: ["go_build"]
3439
steps:
40+
- name: Install Aspell
41+
run: sudo apt-get update && sudo apt-get install -y aspell aspell-en
3542
- uses: actions/checkout@v4
3643
- name: Set up Go
3744
uses: actions/setup-go@v4
@@ -51,6 +58,8 @@ jobs:
5158
runs-on: ubuntu-latest
5259
needs: ["go_build"]
5360
steps:
61+
- name: Install Aspell
62+
run: sudo apt-get update && sudo apt-get install -y aspell aspell-en
5463
- uses: actions/checkout@v4
5564
with:
5665
fetch-depth: 0

Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
FROM golang:alpine as builder
1+
FROM golang:alpine AS builder
22
RUN mkdir /build
33
ADD . /build/
44
WORKDIR /build
55
RUN go build -o check
66

77
FROM alpine:latest
8+
RUN apk --no-cache add aspell aspell-en
89
COPY --from=builder /build/check /check
910
WORKDIR /
1011
ENTRYPOINT ["/check"]

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,24 @@ TagOrder:
9595
### Optional parameters
9696

9797
The program accepts an optional parameter to specify the location (path) of the base of the git repository. This can be useful in certain cases where the checked-out repo is in a non-standard location within the CI environment, compared to the running path from which the check-commit binary is being invoked.
98+
99+
### aspell
100+
101+
to check also spell checking errors aspell was added. it can be configured with `.aspell.yml`
102+
103+
example
104+
```yaml
105+
mode: subject
106+
allowed:
107+
- aspell
108+
```
109+
110+
mode can be set as
111+
112+
- `subject`
113+
- `default` option
114+
- only subject of commit message can will be checked
115+
- `commit`
116+
- whole commit message will be checked
117+
- `disabled`
118+
- check is disabled

aspell/aspell.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package aspell
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"log"
7+
"os/exec"
8+
"slices"
9+
"strings"
10+
)
11+
12+
type Aspell struct {
13+
Mode mode `yaml:"mode"`
14+
AllowedWords []string `yaml:"allowed"`
15+
}
16+
17+
func (a Aspell) checkSingle(data string) error {
18+
var words []string
19+
var badWords []string
20+
21+
checkRes, err := checkWithAspellExec(data)
22+
if checkRes != "" {
23+
words = strings.Split(checkRes, "\n")
24+
}
25+
if err != nil {
26+
return err
27+
}
28+
29+
for _, word := range words {
30+
if len(word) < 1 {
31+
continue
32+
}
33+
if !slices.Contains(a.AllowedWords, word) {
34+
badWords = append(badWords, word)
35+
}
36+
}
37+
38+
if len(badWords) > 0 {
39+
return fmt.Errorf("aspell: %s", badWords)
40+
}
41+
return nil
42+
}
43+
44+
func (a Aspell) Check(subjects []string, content []string) error {
45+
var checks []string
46+
switch a.Mode {
47+
case modeDisabled:
48+
return nil
49+
case modeSubject:
50+
checks = subjects
51+
default:
52+
checks = content
53+
}
54+
55+
var response string
56+
for _, subject := range checks {
57+
if err := a.checkSingle(subject); err != nil {
58+
response += fmt.Sprintf("%s\n", err)
59+
}
60+
}
61+
if len(response) > 0 {
62+
return fmt.Errorf("%s", response)
63+
}
64+
return nil
65+
}
66+
67+
func checkWithAspellExec(subject string) (string, error) {
68+
cmd := exec.Command("aspell", "--list")
69+
cmd.Stdin = strings.NewReader(subject)
70+
71+
var stdout, stderr bytes.Buffer
72+
cmd.Stdout = &stdout
73+
cmd.Stderr = &stderr
74+
err := cmd.Run()
75+
if err != nil {
76+
log.Printf("aspell error: %s, stderr: %s", err, stderr.String())
77+
return "", err
78+
}
79+
80+
return stdout.String() + stderr.String(), nil
81+
}

aspell/aspell_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package aspell
2+
3+
import "testing"
4+
5+
func Test_checkWithAspell(t *testing.T) {
6+
aspell := Aspell{
7+
Mode: modeSubject,
8+
AllowedWords: []string{"config"},
9+
}
10+
tests := []struct {
11+
name string
12+
subject string
13+
wantErr bool
14+
}{
15+
{"OK", "BUG/MEDIUM: config: add default location of path to the configuration file", false},
16+
{"error - flie", "BUG/MEDIUM: config: add default location of path to the configuration flie", true},
17+
{"error - locatoin", "CLEANUP/MEDIUM: config: add default locatoin of path to the configuration file", true},
18+
{"error - locatoin+flie", "CLEANUP/MEDIUM: config: add default locatoin of path to the configuration flie", true},
19+
}
20+
for _, tt := range tests {
21+
t.Run(tt.name, func(t *testing.T) {
22+
err := aspell.checkSingle(tt.subject)
23+
if tt.wantErr && err == nil {
24+
t.Errorf("checkWithAspell() error = %v, wantErr %v", err, tt.wantErr)
25+
}
26+
if !tt.wantErr && err != nil {
27+
t.Errorf("checkWithAspell() error = %v, wantErr %v", err, tt.wantErr)
28+
}
29+
})
30+
}
31+
}

aspell/mode.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package aspell
2+
3+
type mode string
4+
5+
const (
6+
modeDisabled mode = "disabled"
7+
modeSubject mode = "subject"
8+
modeCommit mode = "commit"
9+
// modeAll mode = "all"
10+
)

aspell/new.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package aspell
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"os"
7+
8+
"gopkg.in/yaml.v3"
9+
)
10+
11+
func New(filename string) (Aspell, error) {
12+
var data []byte
13+
var err error
14+
if data, err = os.ReadFile(filename); err != nil {
15+
log.Printf("warning: aspell exceptions file not found (%s)", err)
16+
}
17+
18+
var aspell Aspell
19+
err = yaml.Unmarshal(data, &aspell)
20+
if err != nil {
21+
return Aspell{}, err
22+
}
23+
24+
switch aspell.Mode {
25+
case modeDisabled:
26+
case modeSubject:
27+
case modeCommit:
28+
case "":
29+
aspell.Mode = modeSubject
30+
default:
31+
return Aspell{}, fmt.Errorf("invalid mode: %s", aspell.Mode)
32+
}
33+
34+
log.Printf("aspell mode set to %s", aspell.Mode)
35+
36+
return aspell, nil
37+
}

0 commit comments

Comments
 (0)