-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MAJOR: add aspell as additional check for spelling errors
- Loading branch information
Showing
17 changed files
with
618 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
mode: all | ||
ignore: | ||
- go.mod | ||
- go.sum | ||
- .aspell.yml | ||
allowed: | ||
- aspell | ||
- repo | ||
- yaml | ||
- config |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,11 @@ | ||
FROM golang:alpine as builder | ||
FROM golang:alpine AS builder | ||
RUN mkdir /build | ||
ADD . /build/ | ||
WORKDIR /build | ||
RUN go build -o check | ||
|
||
FROM alpine:latest | ||
RUN apk --no-cache add aspell aspell-en | ||
COPY --from=builder /build/check /check | ||
WORKDIR / | ||
ENTRYPOINT ["/check"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
package aspell | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"log" | ||
"os/exec" | ||
"slices" | ||
"strings" | ||
|
||
"check-commit/match" | ||
|
||
"github.com/fatih/camelcase" | ||
) | ||
|
||
type Aspell struct { | ||
Mode mode `yaml:"mode"` | ||
Ignore []string `yaml:"ignore"` | ||
AllowedWords []string `yaml:"allowed"` | ||
HelpText string `yaml:"-"` | ||
} | ||
|
||
var ( | ||
camelCaseOK = map[string]struct{}{} | ||
camelCaseNotOK = map[string]struct{}{} | ||
) | ||
|
||
func (a Aspell) checkSingle(data string, allowedWords []string) error { | ||
var words []string | ||
var badWords []string | ||
|
||
checkRes, err := checkWithAspellExec(data) | ||
if checkRes != "" { | ||
words = strings.Split(checkRes, "\n") | ||
} | ||
if err != nil { | ||
return err | ||
} | ||
|
||
for _, word := range words { | ||
if len(word) < 1 { | ||
continue | ||
} | ||
if _, ok := camelCaseNotOK[word]; ok { | ||
badWords = append(badWords, word) | ||
continue | ||
} | ||
if _, ok := camelCaseOK[word]; ok { | ||
continue | ||
} | ||
if slices.Contains(a.AllowedWords, word) || slices.Contains(allowedWords, word) { | ||
continue | ||
} | ||
splitted := camelcase.Split(word) | ||
if len(splitted) > 1 { | ||
for _, s := range splitted { | ||
er := a.checkSingle(s, allowedWords) | ||
if er != nil { | ||
camelCaseNotOK[word] = struct{}{} | ||
badWords = append(badWords, word+":"+s) | ||
break | ||
} | ||
} | ||
} else { | ||
camelCaseNotOK[word] = struct{}{} | ||
badWords = append(badWords, word) | ||
} | ||
} | ||
|
||
if len(badWords) > 0 { | ||
return fmt.Errorf("aspell: %s", badWords) | ||
} | ||
return nil | ||
} | ||
|
||
func (a Aspell) Check(subjects []string, commitsFull []string, content []map[string]string) error { | ||
var response string | ||
var checks []string | ||
switch a.Mode { | ||
case modeDisabled: | ||
return nil | ||
case modeSubject: | ||
checks = subjects | ||
case modeCommit: | ||
checks = commitsFull | ||
case modeAll: | ||
for _, file := range content { | ||
for name, v := range file { | ||
nextFile := false | ||
for _, filter := range a.Ignore { | ||
if match.MatchFilter(name, filter) { | ||
// log.Println("File", name, "in ignore list") | ||
nextFile = true | ||
continue | ||
} | ||
} | ||
if nextFile { | ||
continue | ||
} | ||
var imports []string | ||
if strings.HasSuffix(name, ".go") { | ||
imports = match.GetImportWordsFromGoFile(name) | ||
} | ||
if err := a.checkSingle(v, imports); err != nil { | ||
log.Println("File", name, err.Error()) | ||
response += fmt.Sprintf("%s\n", err) | ||
} | ||
} | ||
} | ||
checks = []string{} | ||
default: | ||
checks = subjects | ||
} | ||
|
||
for _, subject := range checks { | ||
if err := a.checkSingle(subject, []string{}); err != nil { | ||
response += fmt.Sprintf("%s\n", err) | ||
} | ||
} | ||
|
||
if len(response) > 0 { | ||
return fmt.Errorf("%s", response) | ||
} | ||
return nil | ||
} | ||
|
||
func checkWithAspellExec(subject string) (string, error) { | ||
cmd := exec.Command("aspell", "--list") | ||
cmd.Stdin = strings.NewReader(subject) | ||
|
||
var stdout, stderr bytes.Buffer | ||
cmd.Stdout = &stdout | ||
cmd.Stderr = &stderr | ||
err := cmd.Run() | ||
if err != nil { | ||
log.Printf("aspell error: %s, stderr: %s", err, stderr.String()) | ||
return "", err | ||
} | ||
|
||
return stdout.String() + stderr.String(), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package aspell | ||
|
||
import "testing" | ||
|
||
func Test_checkWithAspell(t *testing.T) { | ||
aspell := Aspell{ | ||
Mode: modeSubject, | ||
AllowedWords: []string{"config"}, | ||
} | ||
tests := []struct { | ||
name string | ||
subject string | ||
wantErr bool | ||
}{ | ||
{"OK 1", "BUG/MEDIUM: config: add default location of path to the configuration file", false}, | ||
{"OK 2", "BUG/MEDIUM: config: add default location of path to the configuration file xtra", false}, | ||
{"error - flie", "BUG/MEDIUM: config: add default location of path to the configuration flie", true}, | ||
{"error - locatoin", "CLEANUP/MEDIUM: config: add default locatoin of path to the configuration file", true}, | ||
{"error - locatoin+flie", "CLEANUP/MEDIUM: config: add default locatoin of path to the configuration flie", true}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
err := aspell.checkSingle(tt.subject, []string{"xtra"}) | ||
if tt.wantErr && err == nil { | ||
t.Errorf("checkWithAspell() error = %v, wantErr %v", err, tt.wantErr) | ||
} | ||
if !tt.wantErr && err != nil { | ||
t.Errorf("checkWithAspell() error = %v, wantErr %v", err, tt.wantErr) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package aspell | ||
|
||
type mode string | ||
|
||
const ( | ||
modeDisabled mode = "disabled" | ||
modeSubject mode = "subject" | ||
modeCommit mode = "commit" | ||
modeAll mode = "all" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package aspell | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"os" | ||
|
||
"gopkg.in/yaml.v3" | ||
) | ||
|
||
func New(filename string) (Aspell, error) { | ||
var data []byte | ||
var err error | ||
if data, err = os.ReadFile(filename); err != nil { | ||
log.Printf("warning: aspell exceptions file not found (%s)", err) | ||
} | ||
|
||
var aspell Aspell | ||
err = yaml.Unmarshal(data, &aspell) | ||
if err != nil { | ||
return Aspell{}, err | ||
} | ||
|
||
switch aspell.Mode { | ||
case modeDisabled: | ||
case modeSubject: | ||
case modeCommit: | ||
case modeAll: | ||
case "": | ||
aspell.Mode = modeSubject | ||
default: | ||
return Aspell{}, fmt.Errorf("invalid mode: %s", aspell.Mode) | ||
} | ||
|
||
log.Printf("aspell mode set to %s", aspell.Mode) | ||
aspell.HelpText = `aspell can be configured with .aspell.yml file. | ||
content example: | ||
mode: subject | ||
ignore: | ||
- go.mod | ||
- go.sum | ||
- .aspell.yml | ||
allowed: | ||
- aspell | ||
- config | ||
` | ||
return aspell, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"os" | ||
"testing" | ||
|
||
"check-commit/aspell" | ||
) | ||
|
||
func Test_checkWithAspell(t *testing.T) { | ||
aspell, err := aspell.New(".aspell.yml") | ||
if err != nil { | ||
t.Errorf("checkWithAspell() error = %v", err) | ||
} | ||
|
||
readmeFile, err := os.Open("README.md") | ||
if err != nil { | ||
t.Errorf("could not open README.md file: %v", err) | ||
} | ||
defer readmeFile.Close() | ||
|
||
scanner := bufio.NewScanner(readmeFile) | ||
readme := "" | ||
for scanner.Scan() { | ||
readme += scanner.Text() + "\n" | ||
} | ||
if err := scanner.Err(); err != nil { | ||
t.Errorf("could not read README.md file: %v", err) | ||
} | ||
aspell.Check([]string{"subject"}, []string{"body"}, []map[string]string{ | ||
{"README.md": readme}, | ||
}) | ||
} |
Oops, something went wrong.