Add codespell support with configuration and typo fixes (#10393)

* Add GitHub Actions workflow for codespell on master

* Add rudimentary codespell config

* Tune codespell config: skip generated code, ignore camelCase, whitelist domain terms

Add camelCase/PascalCase regex to ignore common Go/Rust/JS identifiers
like allLocations, publishErr, ReadInside, FlushInterval. Also skip
templ-generated *_templ.go files, and whitelist a handful of
short/domain-specific words (visibles, fo, te, ser, bject, unparseable,
keep-alives, tread, anc, ue) that show up as false positives across the
tree.

Co-Authored-By: Claude Code 2.1.217 / Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Fix ambiguous typos and protect false positives

Fixes typos that codespell reports with multiple candidate suggestions
(so `codespell -w` cannot auto-apply them), plus one inline pragma and
one config entry to protect legitimate identifiers.

Manual fixes (single correct answer chosen from context):
- pattens -> patterns (5x) in filer/upload/shell flag help strings
- finded  -> found (2x) in tarantool storage.lua comment
- spacify -> specify (2x) in helm chart values.yaml comment
- wether  -> whether in skiplist.go docstring
- simpe   -> simple in mq schema test case name

False-positive protection:
- Add `//codespell:ignore` next to `source GET's` (possessive of HTTP
  verb) in s3api_object_handlers_copy_stream.go
- Whitelist `auther` in .codespellrc — it's a local variable meaning
  "authenticator" in weed/security/tls.go, not a typo of "author".

Co-Authored-By: Claude Code 2.1.217 / Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Extend codespell ignore list: .git-meta path and thirdparty groupId

Also skip `.git-meta` (scratch dir for commit messages that may contain
typo words verbatim) and whitelist `thirdparty` — it appears as the
literal Maven groupId `org.apache.hadoop.thirdparty` in hdfs3 poms
and cannot be renamed.

Co-Authored-By: Claude Code 2.1.217 / Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [DATALAD RUNCMD] Fix non-ambiguous typos with codespell -w

Auto-applied fixes to the 44 remaining single-suggestion typos across
docs, comments, log messages, tests, config, and one Java pom.

=== Do not change lines below ===
{
 "chain": [],
 "cmd": "uvx codespell -w",
 "exit": 0,
 "extra_inputs": [],
 "inputs": [],
 "outputs": [],
 "pwd": "."
}
^^^ Do not change lines above ^^^

* Revert breaking codespell fixes; whitelist unknwon and atleast

Two of the auto-applied `codespell -w` fixes were false positives that
would break the build/tests:

- go.mod: `github.com/unknwon/goconfig` is a real Go module path — the
  upstream author's GitHub handle is literally `unknwon`. Renaming to
  `unknown` would fail dependency resolution.
- test/benchmark/fuse_db/bin/{sqlite_verify.py,run_mysql.sh,run_sqlite.sh}:
  `atleast` is a literal CLI mode value (a string constant compared and
  passed as a positional argument). Rewriting to `at least` splits it
  into two arguments and breaks the mode check.

Reverted those files and whitelisted both words in .codespellrc so
future runs won't re-suggest the same broken fixes.

Co-Authored-By: Claude Code 2.1.217 / Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Code 2.1.217 / Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yaroslav Halchenko
2026-07-22 14:38:06 -07:00
committed by GitHub
co-authored by Claude Code 2.1.217 / Claude Opus 4.7
parent 6c4eb95a3a
commit 490379bff3
35 changed files with 93 additions and 48 deletions
+22
View File
@@ -0,0 +1,22 @@
[codespell]
# Ref: https://github.com/codespell-project/codespell#using-a-config-file
skip = .git,.git-meta,.gitignore,.gitattributes,*.svg,go.sum,vendor,*.lock,*.css,*.min.*,.codespellrc,*_templ.go
check-hidden = true
# Ignore camelCase and PascalCase identifiers (very common in Go/Rust/JS
# source, e.g. allLocations, publishErr, ReadInside, FlushInterval).
ignore-regex = \b[a-z]+[A-Z]\w*\b|\b[A-Z][a-z]+[A-Z]\w*\b
# visibles: variable name for VisibleInterval collections in filer/mount code
# fo: `*FilerOptions` receiver name (e.g. `func (fo *FilerOptions) ...`)
# te: "truncate error" local variable (e.g. `if te := w.Truncate(end); te != nil`)
# ser: Rust serde serializer variable (`serde_json::ser`, `let mut ser = ...`)
# bject: intentional wildcard test data (e.g. `s3:Get?bject` matching `s3:GetObject`)
# unparseable: accepted alternate spelling used throughout the codebase
# keep-alives: correct plural of the technical term (SSH/HTTP keep-alive)
# tread: valid English word in the idiom "tread carefully" (help text)
# anc: variable abbreviation for "ancestor" in tree/path tests
# ue: appears inside JSON test fixtures with embedded escaped quotes (Bl\"ue)
# auther: local variable meaning "authenticator" (tls.go: `auther := Authenticator{}`)
# thirdparty: literal Maven groupId `org.apache.hadoop.thirdparty` (external, cannot rename)
# unknwon: GitHub username / Go module path (`github.com/unknwon/goconfig`)
# atleast: CLI mode literal string in test/benchmark/fuse_db/bin/sqlite_verify.py
ignore-words-list = visibles,fo,te,ser,bject,unparseable,keep-alives,tread,anc,ue,auther,thirdparty,unknwon,atleast
+23
View File
@@ -0,0 +1,23 @@
# Codespell configuration is within .codespellrc
---
name: Codespell
on:
push:
branches: [master]
pull_request:
branches: [master]
permissions:
contents: read
jobs:
codespell:
name: Check for spelling errors
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Codespell
uses: codespell-project/actions-codespell@8f01853be192eb0f849a5c7d721450e7a467c579 # v2.2
+1 -1
View File
@@ -510,7 +510,7 @@ SeaweedFS Filer uses off-the-shelf stores, such as MySql, Postgres, Sqlite, Mong
### Compared to MinIO ###
Please note, as Apr 25, 2026 MinIO ceased developement. It's strongly discouraged to use that unmaintained software with multiple security bugs.
Please note, as Apr 25, 2026 MinIO ceased development. It's strongly discouraged to use that unmaintained software with multiple security bugs.
MinIO followed AWS S3 closely and was ideal for testing for S3 API. It had good UI, policies, versionings, etc. SeaweedFS is trying to catch up here.
+2 -2
View File
@@ -46,7 +46,7 @@ local filer_metadata = {
delete_by_directory_idx = function(directory)
local space = box.space.filer_metadata
local index = space.index.directory_idx
-- for each finded directories
-- for each found directory
for _, tuple in index:pairs({ directory }, { iterator = 'EQ' }) do
space:delete({ tuple[1], tuple[3] })
end
@@ -64,7 +64,7 @@ local filer_metadata = {
end
-- init results
local results = {}
-- for each finded directories
-- for each found directory
for _, tuple in directory_idx:pairs({ dirPath }, { iterator = 'EQ' }) do
-- filter by name
if filter_filename_func(tuple[3]) then
+2 -2
View File
@@ -125,7 +125,7 @@ master:
# annotations:
# "key": "value"
#
# You may also spacify an existing claim:
# You may also specify an existing claim:
# data:
# type: "existingClaim"
# claimName: "my-pvc"
@@ -351,7 +351,7 @@ volume:
# "key": "value"
# maxVolumes: 0 # If set to zero on non-windows OS, the limit will be auto configured. (default "7")
#
# You may also spacify an existing claim:
# You may also specify an existing claim:
# - name: data
# type: "existingClaim"
# claimName: "my-pvc"
@@ -205,7 +205,7 @@ public class SeaweedInputStream extends InputStream {
* length returned is the length
* as of the time the Stream was opened. Specifically, if there have been
* subsequent appends to the file,
* they wont be reflected in the returned length.
* they won't be reflected in the returned length.
*
* @return length of the file.
* @throws IOException if the stream is closed
@@ -82,7 +82,7 @@ public class SeaweedHadoopInputStream extends FSInputStream {
* length returned is the length
* as of the time the Stream was opened. Specifically, if there have been
* subsequent appends to the file,
* they wont be reflected in the returned length.
* they won't be reflected in the returned length.
*
* @return length of the file.
* @throws IOException if the stream is closed
@@ -29,7 +29,7 @@ public class PutObjectTest
}
/**
* Rigourous Test :-)
* Rigorous Test :-)
*/
public void testApp()
{
@@ -57,7 +57,7 @@ struct DatOwnerInfo {
}
/// Key for orphan-shard reconciliation: collection + volume id. Two
/// collections can re-use the same volume id, and we must only pair
/// collections can reuse the same volume id, and we must only pair
/// shards with their own `.ecx`.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
struct EcKey {
+1 -1
View File
@@ -34,7 +34,7 @@ DEBUG=y ./run.sh
>
> If your output does *not* look like the content in [`results.summary.txt`](./results.summary.txt)
> and it is full of HTTP level exceptions, there is likely an error contacting the `weed` server from
> the container that is runnin the S3 compatibility tests.
> the container that is running the S3 compatibility tests.
>
> There are at least a couple ways to solve this:
>
@@ -61,7 +61,7 @@ func TestS3TablesIntegration(t *testing.T) {
t.Skip("Skipping integration test in short mode")
}
// Re-use the shared cluster started by TestMain.
// Reuse the shared cluster started by TestMain.
client := NewS3TablesClient(sharedCluster.s3Endpoint, testRegion, testAccessKey, testSecretKey)
// Run test suite
+1 -1
View File
@@ -45,7 +45,7 @@
[seaweedfs]
path = @SHARE_PATH@
comment = SeaweedFS share backed by a FUSE mount
browseable = yes
browsable = yes
read only = no
create mask = 0644
directory mask = 0755
+1 -1
View File
@@ -400,7 +400,7 @@ const (
benchBucket = 1000000000 / benchResolution
)
// An efficient statics collecting and rendering
// An efficient statistics collecting and rendering
type stats struct {
data []int
overflow []int
+2 -2
View File
@@ -59,8 +59,8 @@ func init() {
remoteGatewayOptions.createBucketRandomSuffix = cmdFilerRemoteGateway.Flag.Bool("createBucketWithRandomSuffix", true, "add randomized suffix to bucket name to avoid conflicts")
remoteGatewayOptions.readChunkFromFiler = cmdFilerRemoteGateway.Flag.Bool("filerProxy", false, "read file chunks from filer instead of volume servers")
remoteGatewayOptions.timeAgo = cmdFilerRemoteGateway.Flag.Duration("timeAgo", 0, "start time before now. \"300ms\", \"1.5h\" or \"2h45m\". Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\"")
remoteGatewayOptions.include = cmdFilerRemoteGateway.Flag.String("include", "", "pattens of new bucket names, e.g., s3*")
remoteGatewayOptions.exclude = cmdFilerRemoteGateway.Flag.String("exclude", "", "pattens of new bucket names, e.g., local*")
remoteGatewayOptions.include = cmdFilerRemoteGateway.Flag.String("include", "", "patterns of new bucket names, e.g., s3*")
remoteGatewayOptions.exclude = cmdFilerRemoteGateway.Flag.String("exclude", "", "patterns of new bucket names, e.g., local*")
remoteGatewayOptions.clientId = util.RandomInt32()
}
+1 -1
View File
@@ -128,7 +128,7 @@ func init() {
filerOptions.showUIDirectoryDelete = cmdServer.Flag.Bool("filer.ui.deleteDir", true, "enable filer UI show delete directory button")
filerOptions.downloadMaxMBps = cmdServer.Flag.Int("filer.downloadMaxMBps", 0, "download max speed for each download request, in MB per second")
filerOptions.diskType = cmdServer.Flag.String("filer.disk", "", "[hdd|ssd|<tag>] hard drive or solid state drive or any tag")
filerOptions.exposeDirectoryData = cmdServer.Flag.Bool("filer.exposeDirectoryData", true, "expose directory data via filer. If false, filer UI will be innaccessible.")
filerOptions.exposeDirectoryData = cmdServer.Flag.Bool("filer.exposeDirectoryData", true, "expose directory data via filer. If false, filer UI will be inaccessible.")
filerOptions.tusBasePath = cmdServer.Flag.String("filer.tusBasePath", "/.tus", "TUS resumable upload endpoint base path (e.g., /.tus)")
serverOptions.v.port = cmdServer.Flag.Int("volume.port", 8080, "volume server http listen port")
+1 -1
View File
@@ -38,7 +38,7 @@ func init() {
cmdUpload.IsDebug = cmdUpload.Flag.Bool("debug", false, "verbose debug information")
upload.master = cmdUpload.Flag.String("master", "localhost:9333", "SeaweedFS master location")
upload.dir = cmdUpload.Flag.String("dir", "", "Upload the whole folder recursively if specified.")
upload.include = cmdUpload.Flag.String("include", "", "pattens of files to upload, e.g., *.pdf, *.html, ab?d.txt, works together with -dir")
upload.include = cmdUpload.Flag.String("include", "", "patterns of files to upload, e.g., *.pdf, *.html, ab?d.txt, works together with -dir")
upload.replication = cmdUpload.Flag.String("replication", "", "replication type")
upload.collection = cmdUpload.Flag.String("collection", "", "optional collection name")
upload.dataCenter = cmdUpload.Flag.String("dataCenter", "", "optional data center name")
+1 -1
View File
@@ -89,7 +89,7 @@ func (f *Filer) maybeReloadFilerConfiguration(event *filer_pb.SubscribeMetadataR
return
}
glog.V(0).Infof("procesing %v", event)
glog.V(0).Infof("processing %v", event)
if entry.Name == FilerConfName {
f.reloadFilerConfiguration(entry)
}
+1 -1
View File
@@ -1,5 +1,5 @@
Deprecated by redis2.
This implementaiton uses unsorted set. For example, add a directory child via SAdd.
This implementation uses unsorted set. For example, add a directory child via SAdd.
Redis2 moves to sorted set. Adding a child uses ZAddNX.
+1 -1
View File
@@ -133,7 +133,7 @@ func rotate(im image.Image, angle int) image.Image {
// flip returns a flipped version of the image im, according to
// the direction(s) in dir.
// It may flip the imput im in place and return it, or it may allocate a
// It may flip the input im in place and return it, or it may allocate a
// new NRGBA (if im is an *image.YCbCr).
func flip(im image.Image, dir FlipDirection) image.Image {
if dir == 0 {
+1 -1
View File
@@ -30,7 +30,7 @@ import (
// Re-balance topic partitions for publishing
// 1. collect stats from all the brokers
// 2. Rebalance and configure new generation of partitions on brokers
// 3. Tell brokers to close current gneration of publishing.
// 3. Tell brokers to close current generation of publishing.
// Publishers needs to lookup again and publish to the new generation of partitions.
// Re-balance topic partitions for subscribing
+1 -1
View File
@@ -121,7 +121,7 @@ func (p *TopicPublisher) onEachAssignments(generation int, assignments []*mq_pb.
}(job)
jobs = append(jobs, job)
// TODO assuming this is not re-configured so the partitions are fixed.
// better just re-use the existing job
// better just reuse the existing job
p.partition2Buffer.Insert(assignment.Partition.RangeStart, assignment.Partition.RangeStop, job.inputQueue)
}
p.jobs = jobs
+1 -1
View File
@@ -192,7 +192,7 @@ func (h *Handler) handleJoinGroup(connContext *ConnectionContext, correlationID
// leader's upcoming SyncGroup will omit this member. That leaves it
// with an empty Assignment when the group goes Stable, and its own
// SyncGroup then silently serves the empty assignment (the
// CI-observed orphan). Pre-empt that: bump the generation so the
// CI-observed orphan). Preempt that: bump the generation so the
// leader's in-flight SyncGroup fails its generation check and the
// join cycle restarts with the new member in the leader's snapshot.
// (handleSyncGroup also catches this at commit time as a
+1 -1
View File
@@ -61,7 +61,7 @@ func TestStructToSchema(t *testing.T) {
RecordTypeEnd(),
},
{
name: "nested simpe structs",
name: "nested simple structs",
args: args{
instance: struct {
Field1 int
+1 -1
View File
@@ -22,7 +22,7 @@ func TestJsonpMarshalUnmarshal(t *testing.T) {
}
if text, err := m.Marshal(tv); err != nil {
fmt.Printf("marshal eror: %v\n", err)
fmt.Printf("marshal error: %v\n", err)
} else {
fmt.Printf("marshalled: %s\n", string(text))
}
+1 -1
View File
@@ -170,7 +170,7 @@ func TestBuildBucketMetadata(t *testing.T) {
for _, tc := range tcs {
resultBucketMetadata := buildBucketMetadata(iam, tc.filerEntry)
if !reflect.DeepEqual(resultBucketMetadata, tc.expectBucketMetadata) {
t.Fatalf("result is unexpect: \nresult: %v, \nexpect: %v", resultBucketMetadata, tc.expectBucketMetadata)
t.Fatalf("result is unexpected: \nresult: %v, \nexpect: %v", resultBucketMetadata, tc.expectBucketMetadata)
}
}
}
@@ -87,7 +87,7 @@ func (s3a *S3ApiServer) streamCopyChunkRange(
}
// Child context so a terminal error here unblocks both legs
// immediately. Without this, a failed POST closes pipeReader
// (which only fails the producer's writes), but the source GET's
// (which only fails the producer's writes), but the source GET's //codespell:ignore
// read loop would keep draining srcResp.Body in the background
// until EOF — wasting source-volume bandwidth and CPU on a copy
// that's already failed. Cancelling streamCtx tears down both the
+8 -8
View File
@@ -112,28 +112,28 @@ func getREST(httpMetod string, resourceType string) string {
return fmt.Sprintf("REST.%s.%s", httpMetod, resourceType)
}
func getResourceType(object string, query_key string, metod string) (string, bool) {
func getResourceType(object string, query_key string, method string) (string, bool) {
if object == "/" {
switch query_key {
case "delete":
return "BATCH.DELETE.OBJECT", true
case "tagging":
return getREST(metod, "OBJECTTAGGING"), true
return getREST(method, "OBJECTTAGGING"), true
case "lifecycle":
return getREST(metod, "LIFECYCLECONFIGURATION"), true
return getREST(method, "LIFECYCLECONFIGURATION"), true
case "acl":
return getREST(metod, "ACCESSCONTROLPOLICY"), true
return getREST(method, "ACCESSCONTROLPOLICY"), true
case "policy":
return getREST(metod, "BUCKETPOLICY"), true
return getREST(method, "BUCKETPOLICY"), true
default:
return getREST(metod, "BUCKET"), false
return getREST(method, "BUCKET"), false
}
} else {
switch query_key {
case "tagging":
return getREST(metod, "OBJECTTAGGING"), true
return getREST(method, "OBJECTTAGGING"), true
default:
return getREST(metod, "OBJECT"), false
return getREST(method, "OBJECT"), false
}
}
}
+1 -1
View File
@@ -40,7 +40,7 @@ type EntryAttributes struct {
SymlinkTarget string
}
// PermissionError represents a permission-related erro
// PermissionError represents a permission-related error
// CheckFilePermission verifies if a user has the required permission on a path
// It first checks if the path is in the user's home directory with explicit permissions.
+2 -2
View File
@@ -141,8 +141,8 @@ type FileFilter struct {
func newFileFilter(remoteMountCommand *flag.FlagSet) (ff *FileFilter) {
ff = &FileFilter{}
ff.include = remoteMountCommand.String("include", "", "pattens of file names, e.g., *.pdf, *.html, ab?d.txt")
ff.exclude = remoteMountCommand.String("exclude", "", "pattens of file names, e.g., *.pdf, *.html, ab?d.txt")
ff.include = remoteMountCommand.String("include", "", "patterns of file names, e.g., *.pdf, *.html, ab?d.txt")
ff.exclude = remoteMountCommand.String("exclude", "", "patterns of file names, e.g., *.pdf, *.html, ab?d.txt")
ff.minSize = remoteMountCommand.Int64("minSize", -1, "minimum file size in bytes")
ff.maxSize = remoteMountCommand.Int64("maxSize", -1, "maximum file size in bytes")
ff.minAge = remoteMountCommand.Int64("minAge", -1, "minimum file age in seconds (created time)")
+1 -1
View File
@@ -40,7 +40,7 @@ func (c *commandVolumeServerState) Help() string {
Additionally, if any flags are provided, these are applied
to the selected node(s). The command will display the resulting
state for each node *after* the state is updated. For exmaple...
state for each node *after* the state is updated. For example...
volumeServer.state --nodes 192.168.10.111:9000 --maintenanceOn
@@ -152,7 +152,7 @@ func allocate(hMapFile windows.Handle, offset uint64, length uint64, write bool)
mBuffer := MemoryBuffer{}
//align memory allocations to the minium virtual memory allocation size
//align memory allocations to the minimum virtual memory allocation size
dwSysGran := systemInfo.dwAllocationGranularity
start := (offset / uint64(dwSysGran)) * uint64(dwSysGran)
+4 -4
View File
@@ -1,8 +1,8 @@
package needle_map
/* CompactMap is an in-memory map of needle indeces, optimized for memory usage.
/* CompactMap is an in-memory map of needle indices, optimized for memory usage.
*
* It's implemented as a map of sorted indeces segments, which are in turn accessed through binary
* It's implemented as a map of sorted indices segments, which are in turn accessed through binary
* search. This guarantees a best-case scenario (ordered inserts/updates) of O(1) and a worst case
* scenario of O(log n) runtime, with memory usage unaffected by insert ordering.
*
@@ -163,7 +163,7 @@ func (cs *CompactMapSegment) set(key types.NeedleId, offset types.Offset, size t
return
}
// get seeks a map entry by key. Returns an entry pointer, with a boolean specifiying if the entry was found.
// get seeks a map entry by key. Returns an entry pointer, with a boolean specifying if the entry was found.
func (cs *CompactMapSegment) get(key types.NeedleId) (*CompactNeedleValue, bool) {
if i, found := cs.bsearchKey(key); found {
return &cs.list[i], true
@@ -243,7 +243,7 @@ func (cm *CompactMap) Set(key types.NeedleId, offset types.Offset, size types.Si
return cs.set(key, offset, size)
}
// Get seeks a map entry by key. Returns an entry pointer, with a boolean specifiying if the entry was found.
// Get seeks a map entry by key. Returns an entry pointer, with a boolean specifying if the entry was found.
func (cm *CompactMap) Get(key types.NeedleId) (*NeedleValue, bool) {
cm.RLock()
defer cm.RUnlock()
+2 -2
View File
@@ -37,7 +37,7 @@ func TestSegmentBsearchKey(t *testing.T) {
wantFound: false,
},
{
name: "new key, insert at beggining",
name: "new key, insert at beginning",
cs: testSegment,
key: 5,
wantIndex: 0,
@@ -141,7 +141,7 @@ func TestSegmentSet(t *testing.T) {
wantSize types.Size
}{
{
name: "insert at beggining",
name: "insert at beginning",
key: 5, offset: types.Uint32ToOffset(1000), size: 123,
wantOffset: types.Uint32ToOffset(0), wantSize: 0,
},
+1 -1
View File
@@ -23,7 +23,7 @@ type datOwnerInfo struct {
}
// ecKeyForReconcile keys orphan-shard reconciliation by collection + volume
// id. Per-collection grouping matters because two collections can re-use the
// id. Per-collection grouping matters because two collections can reuse the
// same volume id, and we must only pair shards with their own .ecx file.
type ecKeyForReconcile struct {
collection string
+1 -1
View File
@@ -499,7 +499,7 @@ func (t *SkipList) Prev(e *SkipListElement) (*SkipListElement, error) {
// ChangeValue can be used to change the actual value of a node in the skiplist
// without the need of Deleting and reinserting the node again.
// Be advised, that ChangeValue only works, if the actual key from ExtractKey() will stay the same!
// ok is an indicator, wether the value is actually changed.
// ok is an indicator, whether the value is actually changed.
func (t *SkipList) ChangeValue(e *SkipListElement, newValue []byte) (err error) {
// The key needs to stay correct, so this is very important!
e.Value = newValue