Skip to content

Commit 924119b

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

File tree

11 files changed

+184
-71
lines changed

11 files changed

+184
-71
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: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ jobs:
3232
runs-on: ubuntu-latest
3333
needs: ["go_build"]
3434
steps:
35+
- name: Install Aspell
36+
run: sudo apt-get update && sudo apt-get install -y aspell aspell-en
3537
- uses: actions/checkout@v4
3638
- name: Set up Go
3739
uses: actions/setup-go@v4
@@ -51,6 +53,8 @@ jobs:
5153
runs-on: ubuntu-latest
5254
needs: ["go_build"]
5355
steps:
56+
- name: Install Aspell
57+
run: sudo apt-get update && sudo apt-get install -y aspell aspell-en
5458
- uses: actions/checkout@v4
5559
with:
5660
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"]

aspell/aspell.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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(content []string) error {
45+
var response string
46+
for _, subject := range content {
47+
if err := a.checkSingle(subject); err != nil {
48+
response += fmt.Sprintf("%s\n", err)
49+
}
50+
}
51+
if len(response) > 0 {
52+
return fmt.Errorf("%s", response)
53+
}
54+
return nil
55+
}
56+
57+
func checkWithAspellExec(subject string) (string, error) {
58+
cmd := exec.Command("aspell", "--list")
59+
cmd.Stdin = strings.NewReader(subject)
60+
61+
var stdout, stderr bytes.Buffer
62+
cmd.Stdout = &stdout
63+
cmd.Stderr = &stderr
64+
err := cmd.Run()
65+
if err != nil {
66+
log.Printf("aspell error: %s, stderr: %s", err, stderr.String())
67+
return "", err
68+
}
69+
70+
return stdout.String() + stderr.String(), nil
71+
}

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+
}

check.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ import (
1414
"unicode"
1515
"unicode/utf8"
1616

17+
"check-commit/aspell"
18+
1719
"github.com/google/go-github/v56/github"
1820

1921
"github.com/xanzy/go-gitlab"
2022
"golang.org/x/oauth2"
21-
yaml "gopkg.in/yaml.v2"
23+
yaml "gopkg.in/yaml.v3"
2224
)
2325

2426
type patchTypeT struct {
@@ -401,6 +403,11 @@ func main() {
401403
repoPath = os.Args[1]
402404
}
403405

406+
aspellCheck, err := aspell.New(path.Join(repoPath, ".aspell.yml"))
407+
if err != nil {
408+
log.Fatalf("error reading aspell exceptions: %s", err)
409+
}
410+
404411
commitPolicy, err := LoadCommitPolicy(path.Join(repoPath, ".check-commit.yml"))
405412
if err != nil {
406413
log.Fatalf("error reading configuration: %s", err)
@@ -425,5 +432,11 @@ func main() {
425432
log.Fatalf("%s\n", commitPolicy.HelpText)
426433
}
427434

435+
err = aspellCheck.Check(subjects)
436+
if err != nil {
437+
log.Fatalf("%s\n", err)
438+
log.Printf("encountered one or more commit message spelling errors\n")
439+
}
440+
428441
log.Printf("check completed without errors\n")
429442
}

check_different_policy_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"fmt"
55
"testing"
66

7-
yaml "gopkg.in/yaml.v2"
7+
yaml "gopkg.in/yaml.v3"
88
)
99

1010
const customConf = `

go.mod

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,13 @@ require (
66
github.com/google/go-github/v56 v56.0.0
77
github.com/xanzy/go-gitlab v0.107.0
88
golang.org/x/oauth2 v0.21.0
9-
gopkg.in/yaml.v2 v2.4.0
9+
gopkg.in/yaml.v3 v3.0.1
1010
)
1111

1212
require (
13-
github.com/golang/protobuf v1.5.4 // indirect
1413
github.com/google/go-querystring v1.1.0 // indirect
1514
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
1615
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
17-
golang.org/x/net v0.27.0 // indirect
16+
golang.org/x/sys v0.22.0 // indirect
1817
golang.org/x/time v0.5.0 // indirect
19-
google.golang.org/appengine v1.6.8 // indirect
20-
google.golang.org/protobuf v1.34.2 // indirect
2118
)

0 commit comments

Comments
 (0)