@@ -131,26 +131,27 @@ func Build() error {
131131 return nil
132132}
133133
134- // Preflight runs all pre-commit checks: format, tidy, vet, lint, build, test,
135- // race detection, WSL tests, vulnerability scan, strict formatting, dead code
136- // detection, and install verification. If preflight passes, CI will pass.
134+ // Preflight runs all pre-commit checks: format, tidy, vet, lint, WSL lint,
135+ // build, test, race detection, WSL tests, vulnerability scan, strict
136+ // formatting, dead code detection, and install verification. If preflight
137+ // passes, CI will pass.
137138func Preflight () error {
138- fmt .Println ("\n === 1/12 Formatting ===" )
139+ fmt .Println ("\n === 1/13 Formatting ===" )
139140 if err := fmtSources (); err != nil {
140141 return fmt .Errorf ("format: %w" , err )
141142 }
142143
143- fmt .Println ("\n === 2/12 Tidying modules ===" )
144+ fmt .Println ("\n === 2/13 Tidying modules ===" )
144145 if err := run ("go" , "mod" , "tidy" ); err != nil {
145146 return fmt .Errorf ("mod tidy: %w" , err )
146147 }
147148
148- fmt .Println ("\n === 3/12 Vetting ===" )
149+ fmt .Println ("\n === 3/13 Vetting ===" )
149150 if err := run ("go" , "vet" , "./..." ); err != nil {
150151 return fmt .Errorf ("vet: %w" , err )
151152 }
152153
153- fmt .Println ("\n === 4/12 Linting ===" )
154+ fmt .Println ("\n === 4/13 Linting ===" )
154155 if _ , err := exec .LookPath ("golangci-lint" ); err == nil {
155156 if out , err := cmdOutput ("golangci-lint" , "version" ); err == nil {
156157 if ! strings .Contains (out , "golangci-lint has version 2." ) {
@@ -160,31 +161,49 @@ func Preflight() error {
160161 if err := run ("golangci-lint" , "run" ); err != nil {
161162 return fmt .Errorf ("lint: %w" , err )
162163 }
164+ fmt .Println (" Attempting GOOS=linux lint to catch Linux-only files seen in CI" )
165+ if err := runWithEnv (map [string ]string {"GOOS" : "linux" }, "golangci-lint" , "run" ); err != nil {
166+ fmt .Printf (" WARNING: GOOS=linux golangci-lint run failed on %s: %v\n " , runtime .GOOS , err )
167+ }
163168 } else {
164169 fmt .Println (" Skipped (install: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest)" )
165170 }
166171
167- fmt .Println ("\n === 5/12 Building ===" )
172+ fmt .Println ("\n === 5/13 Linting (WSL / Linux) ===" )
173+ if _ , err := exec .LookPath ("wsl" ); err == nil {
174+ wslPath , err := windowsToWSLPath (projectDir ())
175+ if err != nil {
176+ return fmt .Errorf ("WSL path conversion: %w" , err )
177+ }
178+ cmd := fmt .Sprintf ("cd %s && golangci-lint run" , wslPath )
179+ if err := run ("wsl" , "bash" , "-c" , cmd ); err != nil {
180+ return fmt .Errorf ("WSL lint: %w" , err )
181+ }
182+ } else {
183+ fmt .Println (" Skipped (WSL not available)" )
184+ }
185+
186+ fmt .Println ("\n === 6/13 Building ===" )
168187 if err := run ("go" , "build" , "./..." ); err != nil {
169188 return fmt .Errorf ("build: %w" , err )
170189 }
171190
172- fmt .Println ("\n === 6/12 Testing ===" )
191+ fmt .Println ("\n === 7/13 Testing ===" )
173192 if err := run ("go" , "test" , "./..." , "-count=1" ); err != nil {
174193 return fmt .Errorf ("test: %w" , err )
175194 }
176195
177- fmt .Println ("\n === 7/12 Testing (race detector) ===" )
196+ fmt .Println ("\n === 8/13 Testing (race detector) ===" )
178197 if err := run ("go" , "test" , "-race" , "./..." , "-count=1" ); err != nil {
179198 return fmt .Errorf ("race test: %w" , err )
180199 }
181200
182- fmt .Println ("\n === 8/12 Testing (WSL) ===" )
201+ fmt .Println ("\n === 9/13 Testing (WSL) ===" )
183202 if err := TestWSL (); err != nil {
184203 return fmt .Errorf ("WSL test: %w" , err )
185204 }
186205
187- fmt .Println ("\n === 9/12 Vulnerability scan ===" )
206+ fmt .Println ("\n === 10/13 Vulnerability scan ===" )
188207 if _ , err := exec .LookPath ("govulncheck" ); err == nil {
189208 if err := run ("govulncheck" , "./..." ); err != nil {
190209 return fmt .Errorf ("vulncheck: %w" , err )
@@ -193,7 +212,7 @@ func Preflight() error {
193212 fmt .Println (" Skipped (install: go install golang.org/x/vuln/cmd/govulncheck@latest)" )
194213 }
195214
196- fmt .Println ("\n === 10/12 Strict formatting (gofumpt) ===" )
215+ fmt .Println ("\n === 11/13 Strict formatting (gofumpt) ===" )
197216 if _ , err := exec .LookPath ("gofumpt" ); err == nil {
198217 out , _ := cmdOutput ("gofumpt" , "-l" , "." )
199218 if files := strings .TrimSpace (out ); files != "" {
@@ -203,7 +222,7 @@ func Preflight() error {
203222 fmt .Println (" Skipped (install: go install mvdan.cc/gofumpt@latest)" )
204223 }
205224
206- fmt .Println ("\n === 11/12 Dead code detection ===" )
225+ fmt .Println ("\n === 12/13 Dead code detection ===" )
207226 if _ , err := exec .LookPath ("deadcode" ); err == nil {
208227 if err := runDeadcode (); err != nil {
209228 return err
@@ -212,12 +231,12 @@ func Preflight() error {
212231 fmt .Println (" Skipped (install: go install golang.org/x/tools/cmd/deadcode@latest)" )
213232 }
214233
215- fmt .Println ("\n === 12/12 Install verification ===" )
234+ fmt .Println ("\n === 13/13 Install verification ===" )
216235 if err := Install (); err != nil {
217236 return fmt .Errorf ("install: %w" , err )
218237 }
219238
220- fmt .Println ("\n === All 12/12 preflight checks passed — ready to commit ===" )
239+ fmt .Println ("\n === All 13/13 preflight checks passed — ready to commit ===" )
221240 return nil
222241}
223242
@@ -434,6 +453,18 @@ func run(name string, args ...string) error {
434453 return cmd .Run ()
435454}
436455
456+ func runWithEnv (env map [string ]string , name string , args ... string ) error {
457+ cmd := exec .Command (name , args ... )
458+ cmd .Stdout = os .Stdout
459+ cmd .Stderr = os .Stderr
460+ cmd .Dir = projectDir ()
461+ cmd .Env = os .Environ ()
462+ for key , value := range env {
463+ cmd .Env = append (cmd .Env , key + "=" + value )
464+ }
465+ return cmd .Run ()
466+ }
467+
437468func cmdOutput (name string , args ... string ) (string , error ) {
438469 cmd := exec .Command (name , args ... )
439470 cmd .Dir = projectDir ()
0 commit comments