Skip to content

Commit 550c353

Browse files
committed
Extract shared prettier/eslint helpers in Go
- Add runPrettierCheck and runESLintCheck to common.go - Deduplicate 6 check scripts
1 parent 1ee4dfa commit 550c353

7 files changed

Lines changed: 119 additions & 261 deletions

File tree

scripts/check/checks/common.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,107 @@ func Pluralize(count int, singular, plural string) string {
188188
return plural
189189
}
190190

191+
// runPrettierCheck runs Prettier formatting check/fix for a given directory.
192+
// extensions are the file extensions to count (e.g., []string{"*.ts", "*.svelte", "*.css", "*.js"}).
193+
func runPrettierCheck(ctx *CheckContext, dir string, extensions []string) (CheckResult, error) {
194+
// Count files that prettier would check
195+
findArgs := buildFindArgs("src", extensions)
196+
findCmd := exec.Command("find", findArgs...)
197+
findCmd.Dir = dir
198+
findOutput, _ := RunCommand(findCmd, true)
199+
fileCount := 0
200+
if strings.TrimSpace(findOutput) != "" {
201+
fileCount = len(strings.Split(strings.TrimSpace(findOutput), "\n"))
202+
}
203+
204+
// Check which files need formatting (--list-different lists them)
205+
// Note: prettier exits with code 1 if files differ, so we ignore the error
206+
// Prettier's default behavior respects .gitignore files in current dir and parents
207+
checkCmd := exec.Command("pnpm", "exec", "prettier", "--list-different", ".")
208+
checkCmd.Dir = dir
209+
checkOutput, _ := RunCommand(checkCmd, true)
210+
211+
// Parse files that need formatting
212+
var needsFormat []string
213+
if strings.TrimSpace(checkOutput) != "" {
214+
needsFormat = strings.Split(strings.TrimSpace(checkOutput), "\n")
215+
}
216+
217+
if ctx.CI {
218+
if len(needsFormat) > 0 {
219+
return CheckResult{}, fmt.Errorf("code is not formatted, run pnpm format locally\n%s", indentOutput(checkOutput))
220+
}
221+
return Success(fmt.Sprintf("%d %s already formatted", fileCount, Pluralize(fileCount, "file", "files"))), nil
222+
}
223+
224+
// Non-CI mode: format if needed
225+
if len(needsFormat) > 0 {
226+
fmtCmd := exec.Command("pnpm", "format")
227+
fmtCmd.Dir = dir
228+
output, err := RunCommand(fmtCmd, true)
229+
if err != nil {
230+
return CheckResult{}, fmt.Errorf("prettier formatting failed\n%s", indentOutput(output))
231+
}
232+
return SuccessWithChanges(fmt.Sprintf("Formatted %d of %d %s", len(needsFormat), fileCount, Pluralize(fileCount, "file", "files"))), nil
233+
}
234+
235+
return Success(fmt.Sprintf("%d %s already formatted", fileCount, Pluralize(fileCount, "file", "files"))), nil
236+
}
237+
238+
// runESLintCheck runs ESLint check/fix for a given directory.
239+
// extensions are the file extensions to count (e.g., []string{"*.ts", "*.svelte", "*.js"}).
240+
// If requireConfig is true, skips when eslint.config.js is missing.
241+
func runESLintCheck(ctx *CheckContext, dir string, extensions []string, requireConfig bool) (CheckResult, error) {
242+
if requireConfig {
243+
if _, err := os.Stat(filepath.Join(dir, "eslint.config.js")); os.IsNotExist(err) {
244+
return Skipped("no eslint.config.js"), nil
245+
}
246+
}
247+
248+
// Count lintable files
249+
findArgs := buildFindArgs("src", extensions)
250+
findCmd := exec.Command("find", findArgs...)
251+
findCmd.Dir = dir
252+
findOutput, _ := RunCommand(findCmd, true)
253+
fileCount := 0
254+
if strings.TrimSpace(findOutput) != "" {
255+
fileCount = len(strings.Split(strings.TrimSpace(findOutput), "\n"))
256+
}
257+
258+
var cmd *exec.Cmd
259+
if ctx.CI {
260+
cmd = exec.Command("pnpm", "lint")
261+
} else {
262+
cmd = exec.Command("pnpm", "lint:fix")
263+
}
264+
cmd.Dir = dir
265+
output, err := RunCommand(cmd, true)
266+
if err != nil {
267+
if ctx.CI {
268+
return CheckResult{}, fmt.Errorf("lint errors found, run pnpm lint:fix locally\n%s", indentOutput(output))
269+
}
270+
return CheckResult{}, fmt.Errorf("eslint found unfixable errors\n%s", indentOutput(output))
271+
}
272+
273+
if fileCount > 0 {
274+
return Success(fmt.Sprintf("%d %s passed", fileCount, Pluralize(fileCount, "file", "files"))), nil
275+
}
276+
return Success("All files passed"), nil
277+
}
278+
279+
// buildFindArgs constructs arguments for a find command to locate files with given extensions.
280+
func buildFindArgs(searchDir string, extensions []string) []string {
281+
args := []string{searchDir, "-type", "f", "("}
282+
for i, ext := range extensions {
283+
if i > 0 {
284+
args = append(args, "-o")
285+
}
286+
args = append(args, "-name", ext)
287+
}
288+
args = append(args, ")")
289+
return args
290+
}
291+
191292
// GetGoDirectories returns all directories in the repo that contain Go code.
192293
// Each returned path is relative to rootDir.
193294
func GetGoDirectories() []string {
Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,9 @@
11
package checks
22

3-
import (
4-
"fmt"
5-
"os/exec"
6-
"path/filepath"
7-
"strings"
8-
)
3+
import "path/filepath"
94

105
// RunDesktopESLint lints and fixes code with ESLint.
116
func RunDesktopESLint(ctx *CheckContext) (CheckResult, error) {
12-
desktopDir := filepath.Join(ctx.RootDir, "apps", "desktop")
13-
14-
// Count lintable files
15-
findCmd := exec.Command("find", "src", "-type", "f", "(", "-name", "*.ts", "-o", "-name", "*.svelte", "-o", "-name", "*.js", ")")
16-
findCmd.Dir = desktopDir
17-
findOutput, _ := RunCommand(findCmd, true)
18-
fileCount := 0
19-
if strings.TrimSpace(findOutput) != "" {
20-
fileCount = len(strings.Split(strings.TrimSpace(findOutput), "\n"))
21-
}
22-
23-
var cmd *exec.Cmd
24-
if ctx.CI {
25-
cmd = exec.Command("pnpm", "lint")
26-
} else {
27-
cmd = exec.Command("pnpm", "lint:fix")
28-
}
29-
cmd.Dir = desktopDir
30-
output, err := RunCommand(cmd, true)
31-
if err != nil {
32-
if ctx.CI {
33-
return CheckResult{}, fmt.Errorf("lint errors found, run pnpm lint:fix locally\n%s", indentOutput(output))
34-
}
35-
return CheckResult{}, fmt.Errorf("eslint found unfixable errors\n%s", indentOutput(output))
36-
}
37-
38-
if fileCount > 0 {
39-
return Success(fmt.Sprintf("%d %s passed", fileCount, Pluralize(fileCount, "file", "files"))), nil
40-
}
41-
return Success("All files passed"), nil
7+
dir := filepath.Join(ctx.RootDir, "apps", "desktop")
8+
return runESLintCheck(ctx, dir, []string{"*.ts", "*.svelte", "*.js"}, false)
429
}
Lines changed: 3 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,9 @@
11
package checks
22

3-
import (
4-
"fmt"
5-
"os/exec"
6-
"path/filepath"
7-
"strings"
8-
)
3+
import "path/filepath"
94

105
// RunDesktopPrettier formats code with Prettier.
116
func RunDesktopPrettier(ctx *CheckContext) (CheckResult, error) {
12-
desktopDir := filepath.Join(ctx.RootDir, "apps", "desktop")
13-
14-
// Count files that prettier would check
15-
findCmd := exec.Command("find", "src", "-type", "f", "(", "-name", "*.ts", "-o", "-name", "*.svelte", "-o", "-name", "*.css", "-o", "-name", "*.js", ")")
16-
findCmd.Dir = desktopDir
17-
findOutput, _ := RunCommand(findCmd, true)
18-
fileCount := 0
19-
if strings.TrimSpace(findOutput) != "" {
20-
fileCount = len(strings.Split(strings.TrimSpace(findOutput), "\n"))
21-
}
22-
23-
// Check which files need formatting (--list-different lists them)
24-
// Note: prettier exits with code 1 if files differ, so we ignore the error
25-
// Prettier's default behavior respects .gitignore files in current dir and parents
26-
checkCmd := exec.Command("pnpm", "exec", "prettier", "--list-different", ".")
27-
checkCmd.Dir = desktopDir
28-
checkOutput, _ := RunCommand(checkCmd, true)
29-
30-
// Parse files that need formatting
31-
var needsFormat []string
32-
if strings.TrimSpace(checkOutput) != "" {
33-
needsFormat = strings.Split(strings.TrimSpace(checkOutput), "\n")
34-
}
35-
36-
if ctx.CI {
37-
if len(needsFormat) > 0 {
38-
return CheckResult{}, fmt.Errorf("code is not formatted, run pnpm format locally\n%s", indentOutput(checkOutput))
39-
}
40-
return Success(fmt.Sprintf("%d %s already formatted", fileCount, Pluralize(fileCount, "file", "files"))), nil
41-
}
42-
43-
// Non-CI mode: format if needed
44-
if len(needsFormat) > 0 {
45-
fmtCmd := exec.Command("pnpm", "format")
46-
fmtCmd.Dir = desktopDir
47-
output, err := RunCommand(fmtCmd, true)
48-
if err != nil {
49-
return CheckResult{}, fmt.Errorf("prettier formatting failed\n%s", indentOutput(output))
50-
}
51-
return SuccessWithChanges(fmt.Sprintf("Formatted %d of %d %s", len(needsFormat), fileCount, Pluralize(fileCount, "file", "files"))), nil
52-
}
53-
54-
return Success(fmt.Sprintf("%d %s already formatted", fileCount, Pluralize(fileCount, "file", "files"))), nil
7+
dir := filepath.Join(ctx.RootDir, "apps", "desktop")
8+
return runPrettierCheck(ctx, dir, []string{"*.ts", "*.svelte", "*.css", "*.js"})
559
}
Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,9 @@
11
package checks
22

3-
import (
4-
"fmt"
5-
"os"
6-
"os/exec"
7-
"path/filepath"
8-
"strings"
9-
)
3+
import "path/filepath"
104

115
// RunLicenseServerESLint runs ESLint on the license server.
126
func RunLicenseServerESLint(ctx *CheckContext) (CheckResult, error) {
13-
serverDir := filepath.Join(ctx.RootDir, "apps", "license-server")
14-
15-
// Check if eslint.config.js exists
16-
if _, err := os.Stat(filepath.Join(serverDir, "eslint.config.js")); os.IsNotExist(err) {
17-
return Skipped("no eslint.config.js"), nil
18-
}
19-
20-
// Count lintable files
21-
findCmd := exec.Command("find", "src", "-type", "f", "(", "-name", "*.ts", "-o", "-name", "*.js", ")")
22-
findCmd.Dir = serverDir
23-
findOutput, _ := RunCommand(findCmd, true)
24-
fileCount := 0
25-
if strings.TrimSpace(findOutput) != "" {
26-
fileCount = len(strings.Split(strings.TrimSpace(findOutput), "\n"))
27-
}
28-
29-
var cmd *exec.Cmd
30-
if ctx.CI {
31-
cmd = exec.Command("pnpm", "lint")
32-
} else {
33-
cmd = exec.Command("pnpm", "lint:fix")
34-
}
35-
cmd.Dir = serverDir
36-
output, err := RunCommand(cmd, true)
37-
if err != nil {
38-
return CheckResult{}, fmt.Errorf("eslint failed\n%s", indentOutput(output))
39-
}
40-
41-
if fileCount > 0 {
42-
return Success(fmt.Sprintf("%d %s passed", fileCount, Pluralize(fileCount, "file", "files"))), nil
43-
}
44-
return Success("All files passed"), nil
7+
dir := filepath.Join(ctx.RootDir, "apps", "license-server")
8+
return runESLintCheck(ctx, dir, []string{"*.ts", "*.js"}, true)
459
}
Lines changed: 3 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,9 @@
11
package checks
22

3-
import (
4-
"fmt"
5-
"os/exec"
6-
"path/filepath"
7-
"strings"
8-
)
3+
import "path/filepath"
94

105
// RunLicenseServerPrettier runs Prettier on the license server.
116
func RunLicenseServerPrettier(ctx *CheckContext) (CheckResult, error) {
12-
serverDir := filepath.Join(ctx.RootDir, "apps", "license-server")
13-
14-
// Count files
15-
findCmd := exec.Command("find", "src", "-type", "f", "(", "-name", "*.ts", "-o", "-name", "*.js", ")")
16-
findCmd.Dir = serverDir
17-
findOutput, _ := RunCommand(findCmd, true)
18-
fileCount := 0
19-
if strings.TrimSpace(findOutput) != "" {
20-
fileCount = len(strings.Split(strings.TrimSpace(findOutput), "\n"))
21-
}
22-
23-
// Check which files need formatting (--list-different lists them)
24-
// Note: prettier exits with code 1 if files differ, so we ignore the error
25-
// Prettier's default behavior respects .gitignore files in current dir and parents
26-
checkCmd := exec.Command("pnpm", "exec", "prettier", "--list-different", ".")
27-
checkCmd.Dir = serverDir
28-
checkOutput, _ := RunCommand(checkCmd, true)
29-
30-
// Parse files that need formatting
31-
var needsFormat []string
32-
if strings.TrimSpace(checkOutput) != "" {
33-
needsFormat = strings.Split(strings.TrimSpace(checkOutput), "\n")
34-
}
35-
36-
if ctx.CI {
37-
if len(needsFormat) > 0 {
38-
return CheckResult{}, fmt.Errorf("code is not formatted, run pnpm format locally\n%s", indentOutput(checkOutput))
39-
}
40-
return Success(fmt.Sprintf("%d %s already formatted", fileCount, Pluralize(fileCount, "file", "files"))), nil
41-
}
42-
43-
// Non-CI mode: format if needed
44-
if len(needsFormat) > 0 {
45-
fmtCmd := exec.Command("pnpm", "format")
46-
fmtCmd.Dir = serverDir
47-
output, err := RunCommand(fmtCmd, true)
48-
if err != nil {
49-
return CheckResult{}, fmt.Errorf("prettier formatting failed\n%s", indentOutput(output))
50-
}
51-
return SuccessWithChanges(fmt.Sprintf("Formatted %d of %d %s", len(needsFormat), fileCount, Pluralize(fileCount, "file", "files"))), nil
52-
}
53-
54-
return Success(fmt.Sprintf("%d %s already formatted", fileCount, Pluralize(fileCount, "file", "files"))), nil
7+
dir := filepath.Join(ctx.RootDir, "apps", "license-server")
8+
return runPrettierCheck(ctx, dir, []string{"*.ts", "*.js"})
559
}
Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,9 @@
11
package checks
22

3-
import (
4-
"fmt"
5-
"os"
6-
"os/exec"
7-
"path/filepath"
8-
"strings"
9-
)
3+
import "path/filepath"
104

115
// RunWebsiteESLint runs ESLint on the website.
126
func RunWebsiteESLint(ctx *CheckContext) (CheckResult, error) {
13-
websiteDir := filepath.Join(ctx.RootDir, "apps", "website")
14-
15-
// Check if eslint.config.js exists
16-
if _, err := os.Stat(filepath.Join(websiteDir, "eslint.config.js")); os.IsNotExist(err) {
17-
return Skipped("no eslint.config.js"), nil
18-
}
19-
20-
// Count lintable files
21-
findCmd := exec.Command("find", "src", "-type", "f", "(", "-name", "*.ts", "-o", "-name", "*.astro", "-o", "-name", "*.js", ")")
22-
findCmd.Dir = websiteDir
23-
findOutput, _ := RunCommand(findCmd, true)
24-
fileCount := 0
25-
if strings.TrimSpace(findOutput) != "" {
26-
fileCount = len(strings.Split(strings.TrimSpace(findOutput), "\n"))
27-
}
28-
29-
var cmd *exec.Cmd
30-
if ctx.CI {
31-
cmd = exec.Command("pnpm", "lint")
32-
} else {
33-
cmd = exec.Command("pnpm", "lint:fix")
34-
}
35-
cmd.Dir = websiteDir
36-
output, err := RunCommand(cmd, true)
37-
if err != nil {
38-
return CheckResult{}, fmt.Errorf("eslint failed\n%s", indentOutput(output))
39-
}
40-
41-
if fileCount > 0 {
42-
return Success(fmt.Sprintf("%d %s passed", fileCount, Pluralize(fileCount, "file", "files"))), nil
43-
}
44-
return Success("All files passed"), nil
7+
dir := filepath.Join(ctx.RootDir, "apps", "website")
8+
return runESLintCheck(ctx, dir, []string{"*.ts", "*.astro", "*.js"}, true)
459
}

0 commit comments

Comments
 (0)