From b534fb0714617832e61c86c0d1fe5aae15ad8bf2 Mon Sep 17 00:00:00 2001 From: tuxedomm <273098272+tuxedomm@users.noreply.github.com> Date: Wed, 8 Apr 2026 20:41:38 +0800 Subject: [PATCH] chore: add depguard and forbidigo rules to guide FileIO adoption - Add depguard linter to block shortcuts/ from importing internal/vfs directly (must use runtime.FileIO() instead) - Add forbidigo rules for os.* filesystem ops, IO streams, os.Exit, and filepath.* functions that bypass vfs - Split os.Remove / os.RemoveAll into separate patterns with accurate guidance (RemoveAll not yet in vfs) - Use compact regex groups for maintainability, no duplicate or shadowed patterns Change-Id: I9e45ab07ca58a61b86bdcea9f1f2cc6181c974bc --- .golangci.yml | 97 ++++++++++++++++++++------------------------------- 1 file changed, 38 insertions(+), 59 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index da2d5320b..faa9ee79d 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -27,6 +27,7 @@ linters: - reassign # checks that package variables are not reassigned - unconvert # removes unnecessary type conversions - unused # checks for unused constants, variables, functions and types + - depguard # blocks forbidden package imports - forbidigo # forbids specific function calls # To enable later after fixing existing issues: @@ -45,6 +46,7 @@ linters: linters: - bodyclose - gocritic + - depguard - forbidigo - path-except: (shortcuts/|internal/) linters: @@ -54,79 +56,56 @@ linters: - forbidigo settings: + depguard: + rules: + shortcuts-no-vfs: + files: + - "**/shortcuts/**" + deny: + - pkg: "github.com/larksuite/cli/internal/vfs" + desc: >- + shortcuts must not import internal/vfs directly. + Use runtime.FileIO() for file operations or runtime.ValidatePath() for path validation. + - pkg: "github.com/larksuite/cli/internal/vfs/localfileio" + desc: >- + shortcuts must not import internal/vfs/localfileio directly. + Use runtime.FileIO() for file operations or runtime.ValidatePath() for path validation. forbidigo: forbid: - # ── Filesystem operations: use internal/vfs instead ── - - pattern: os\.Stat\b - msg: "use vfs.Stat() from internal/vfs" - - pattern: os\.Lstat\b - msg: "use vfs.Lstat() from internal/vfs" - - pattern: os\.Open\b - msg: "use vfs.Open() from internal/vfs" - - pattern: os\.OpenFile\b - msg: "use vfs.OpenFile() from internal/vfs" - - pattern: os\.Create\b - msg: "use vfs.OpenFile() from internal/vfs" - - pattern: os\.CreateTemp\b + # ── os: already wrapped in internal/vfs ── + - pattern: os\.(Stat|Lstat|Open|OpenFile|Rename|ReadFile|WriteFile|Getwd|UserHomeDir|ReadDir)\b + msg: "use the corresponding vfs.Xxx() from internal/vfs" + - pattern: os\.(Create|CreateTemp|MkdirTemp)\b msg: >- - internal/: use vfs.CreateTemp() from internal/vfs. - shortcuts/: avoid temp files entirely — use io.Reader streaming or in-memory buffers instead. - - pattern: os\.Mkdir\b - msg: "use vfs.MkdirAll() from internal/vfs" - - pattern: os\.MkdirAll\b + internal/: use vfs.CreateTemp() or vfs.OpenFile(). + shortcuts/: avoid temp files — use io.Reader streaming or in-memory buffers. + - pattern: os\.Mkdir(All)?\b msg: "use vfs.MkdirAll() from internal/vfs" - pattern: os\.Remove\b msg: >- internal/: use vfs.Remove() from internal/vfs. - shortcuts/: avoid temp files entirely — use io.Reader streaming or in-memory buffers instead. + shortcuts/: avoid temp files — use io.Reader streaming or in-memory buffers. - pattern: os\.RemoveAll\b msg: >- internal/: add RemoveAll to internal/vfs/fs.go first, then use vfs.RemoveAll(). - shortcuts/: avoid temp files entirely — use io.Reader streaming or in-memory buffers instead. - - pattern: os\.Rename\b - msg: "use vfs.Rename() from internal/vfs" - - pattern: os\.ReadFile\b - msg: "use vfs.ReadFile() from internal/vfs" - - pattern: os\.WriteFile\b - msg: "use vfs.WriteFile() from internal/vfs" - - pattern: os\.ReadDir\b - msg: "add ReadDir to internal/vfs/fs.go first, then use vfs.ReadDir()" - - pattern: os\.Getwd\b - msg: "use vfs.Getwd() from internal/vfs" - - pattern: os\.Chdir\b - msg: "add Chdir to internal/vfs/fs.go first, then use vfs.Chdir()" - - pattern: os\.UserHomeDir\b - msg: "use vfs.UserHomeDir() from internal/vfs" - - pattern: os\.Chmod\b - msg: "add Chmod to internal/vfs/fs.go first, then use vfs.Chmod()" - - pattern: os\.Chown\b - msg: "add Chown to internal/vfs/fs.go first, then use vfs.Chown()" - - pattern: os\.Lchown\b - msg: "add Lchown to internal/vfs/fs.go first, then use vfs.Lchown()" - - pattern: os\.Link\b - msg: "add Link to internal/vfs/fs.go first, then use vfs.Link()" - - pattern: os\.Symlink\b - msg: "add Symlink to internal/vfs/fs.go first, then use vfs.Symlink()" - - pattern: os\.Readlink\b - msg: "add Readlink to internal/vfs/fs.go first, then use vfs.Readlink()" - - pattern: os\.Truncate\b - msg: "add Truncate to internal/vfs/fs.go first, then use vfs.Truncate()" - - pattern: os\.DirFS\b - msg: "add DirFS to internal/vfs/fs.go first, then use vfs.DirFS()" - - pattern: os\.SameFile\b - msg: "add SameFile to internal/vfs/fs.go first, then use vfs.SameFile()" - # ── IO streams: use IOStreams from cmdutil instead ── - - pattern: os\.Stdin\b - msg: "use IOStreams.In instead of os.Stdin" - - pattern: os\.Stdout\b - msg: "use IOStreams.Out instead of os.Stdout" - - pattern: os\.Stderr\b - msg: "use IOStreams.ErrOut instead of os.Stderr" - # ── Process-level rules ── + shortcuts/: avoid temp files — use io.Reader streaming or in-memory buffers. + # ── os: not yet in vfs — add to vfs/fs.go first ── + - pattern: os\.(Chdir|Chmod|Chown|Lchown|Chtimes|CopyFS|DirFS|Link|Symlink|Readlink|Truncate|SameFile)\b + msg: "add this function to internal/vfs/fs.go first, then use vfs.Xxx()" + # ── os: IO streams ── + - pattern: os\.Std(in|out|err)\b + msg: "use IOStreams (In/Out/ErrOut) instead of os.Stdin/Stdout/Stderr" + # ── os: process ── - pattern: os\.Exit\b msg: >- Do not use os.Exit in shortcuts/. Return an error instead and let the caller (cmd layer) decide how to terminate. + # ── filepath: functions that access the filesystem ── + - pattern: filepath\.(EvalSymlinks|Walk|WalkDir|Glob|Abs)\b + msg: >- + These filepath functions access the filesystem directly. + internal/: use vfs helpers or localfileio path validation. + shortcuts/: use runtime.ValidatePath() or runtime.FileIO(). analyze-types: true gocritic: disabled-checks: