Skip to content

Commit ce8498e

Browse files
jongioCopilot
andcommitted
fix: resolve CI lint failures, add WSL lint to preflight, chain pages deploy
- Fix goconst: extract coalesceCwd constant in store.go - Fix prealloc: preallocate argv slice in launch_unix.go - Fix unused: add nolint directive for build-tag stub launchInPlaceUnix - Add WSL lint step to preflight (now 13 steps) to catch Linux-only build-tag file issues that Windows golangci-lint misses - Add cross-GOOS lint attempt (GOOS=linux) as best-effort fallback - Chain pages deployment into release workflow (runs after goreleaser) - Add workflow_call trigger to pages.yml for reusable workflow support Root cause: golangci-lint on Windows skips //go:build !windows files, so lint issues in Unix-only code were invisible to local preflight but caught by CI running on Linux. Co-authored-by: Copilot <[email protected]>
1 parent 604453e commit ce8498e

5 files changed

Lines changed: 64 additions & 19 deletions

File tree

.github/workflows/pages.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ on:
88
- 'README.md'
99
- 'CHANGELOG.md'
1010
workflow_dispatch:
11+
workflow_call:
1112

1213
permissions:
1314
contents: read

.github/workflows/release.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,11 @@ jobs:
4848
args: release --clean
4949
env:
5050
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
51+
52+
pages:
53+
needs: release
54+
uses: ./.github/workflows/pages.yml
55+
permissions:
56+
contents: read
57+
pages: write
58+
id-token: write

internal/data/store.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ const (
3232

3333
// limitClause is the SQL fragment appended to queries with a row cap.
3434
limitClause = " LIMIT ?"
35+
36+
// coalesceCwd normalizes NULL session directories to empty strings.
37+
coalesceCwd = "COALESCE(s.cwd, '')"
3538
)
3639

3740
// Store provides read-only access to the Copilot CLI session store.
@@ -288,15 +291,15 @@ func pivotExpr(p PivotField) string {
288291
case PivotByDate:
289292
return "SUBSTR(" + lastActiveExpr + ", 1, 10)"
290293
default: // PivotByFolder and any unknown value
291-
return "COALESCE(s.cwd, '')"
294+
return coalesceCwd
292295
}
293296
}
294297

295298
// sessionColumns is the shared SELECT list used by session queries.
296299
// last_active_at is computed as the most recent turn timestamp, falling
297300
// back to updated_at then created_at so that reindex-clobbered dates
298301
// don't make old sessions appear recent.
299-
var sessionColumns = `s.id, COALESCE(s.cwd,''), COALESCE(s.repository,''), COALESCE(s.branch,''),
302+
var sessionColumns = `s.id, ` + coalesceCwd + `, COALESCE(s.repository,''), COALESCE(s.branch,''),
300303
COALESCE(s.summary,''), COALESCE(s.created_at,''), COALESCE(s.updated_at,''),
301304
` + lastActiveExpr + ` AS last_active_at,
302305
(SELECT COUNT(*) FROM turns t WHERE t.session_id = s.id) AS turn_count,

internal/platform/launch_unix.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,16 @@ func filterEnv(env []string) []string {
4141
return result
4242
}
4343

44+
//nolint:unused // Referenced via build-tagged launch paths; Windows keeps a stub with the same symbol.
4445
func launchInPlaceUnix(shell ShellInfo, resumeCmd string, cwd string) error {
4546
if cwd != "" {
4647
// Best-effort: change directory before exec replaces the process.
4748
// If chdir fails we still launch from the current directory.
4849
_ = os.Chdir(cwd)
4950
}
5051

51-
argv := []string{shell.Path}
52+
argv := make([]string, 0, 1+len(shell.Args)+2)
53+
argv = append(argv, shell.Path)
5254
argv = append(argv, shell.Args...)
5355
argv = append(argv, "-c", resumeCmd)
5456

magefile.go

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
137138
func 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+
437468
func cmdOutput(name string, args ...string) (string, error) {
438469
cmd := exec.Command(name, args...)
439470
cmd.Dir = projectDir()

0 commit comments

Comments
 (0)