this repo has no description
1package main
2
3import (
4 "context"
5 "errors"
6 "fmt"
7 "io/fs"
8 "os"
9 "os/exec"
10 "os/signal"
11 "path/filepath"
12 "syscall"
13)
14
15var debug = os.Getenv("DEBUG") == "1"
16
17func main() {
18 ctx := context.Background()
19 ctx, done := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM)
20 defer done()
21
22 err := run(ctx)
23 if err != nil {
24 fmt.Fprintln(os.Stderr, "pre-commit", err)
25 os.Exit(1)
26 }
27}
28
29func run(ctx context.Context) error {
30 tools, err := selectTools()
31 if err != nil {
32 return err
33 }
34
35 for i, tool := range tools {
36 if debug {
37 fmt.Fprintln(os.Stderr, "running tool", i, tool.name)
38 }
39 out, err := tool.run(ctx)
40 var exit *exec.ExitError
41 if errors.As(err, &exit) {
42 if tool.allowfail {
43 continue
44 }
45 return fmt.Errorf("tool %d %q exited with nonzero status %d, out:\n%s", i, tool.name, exit.ExitCode(), out)
46 } else if err != nil {
47 return fmt.Errorf("tool %d %q unexpected error: %w", i, tool.name, err)
48 }
49 }
50 return nil
51}
52
53type tool struct {
54 name string
55 run func(ctx context.Context) ([]byte, error)
56 allowfail bool
57}
58
59func selectTools() ([]tool, error) {
60 var cuefiles, gofiles []string
61 var prettier, terraform, misspell bool
62 err := filepath.WalkDir(".", func(p string, d fs.DirEntry, err error) error {
63 if err != nil || d.IsDir() {
64 if d.Name() == ".git" {
65 return fs.SkipDir
66 }
67 return err
68 }
69 switch filepath.Ext(d.Name()) {
70 case ".css", ".html", ".json", ".md", ".yaml":
71 prettier = true
72 misspell = true
73 case ".go":
74 gofiles = append(gofiles, p)
75 misspell = true
76 case ".cue":
77 fmt.Println(p, d.Name())
78 cuefiles = append(cuefiles, p)
79 case ".tf":
80 terraform = true
81 }
82 return nil
83 })
84 if err != nil {
85 return nil, fmt.Errorf("select tools: walk over '.': %w", err)
86 }
87
88 var tools []tool
89 if misspell {
90 tools = append(tools, tool{
91 name: "misspell",
92 run: func(ctx context.Context) ([]byte, error) {
93 return exec.CommandContext(ctx,
94 "misspell", "-w", "-q", ".",
95 ).CombinedOutput()
96 },
97 })
98 }
99 if prettier {
100 tools = append(tools, tool{
101 name: "prettier",
102 run: func(ctx context.Context) ([]byte, error) {
103 return exec.CommandContext(ctx,
104 "prettier", "-w", ".",
105 ).CombinedOutput()
106 },
107 })
108 }
109 if len(cuefiles) > 0 {
110 tools = append(tools, tool{
111 name: "cue fmt",
112 run: func(ctx context.Context) ([]byte, error) {
113 return exec.CommandContext(ctx,
114 "cue", append([]string{"fmt"}, cuefiles...)...,
115 ).CombinedOutput()
116 },
117 })
118 }
119 if terraform {
120 tools = append(tools, tool{
121 name: "terraform fmt",
122 run: func(ctx context.Context) ([]byte, error) {
123 return exec.CommandContext(ctx,
124 "terraform", "fmt", "-write", "-recursive", ".",
125 ).CombinedOutput()
126 },
127 })
128 }
129 if len(gofiles) > 0 {
130 godirsm := make(map[string]struct{})
131 for _, dir := range gofiles {
132 godirsm[filepath.Dir(dir)] = struct{}{}
133 }
134 godirs := make([]string, 0, len(godirsm))
135 for dir := range godirsm {
136 godirs = append(godirs, dir)
137 }
138 tools = append(tools, tool{
139 name: "go mod tidy",
140 run: func(ctx context.Context) ([]byte, error) {
141 return exec.CommandContext(ctx,
142 "go", "mod", "tidy",
143 ).CombinedOutput()
144 },
145 }, tool{
146 name: "gofumpt",
147 run: func(ctx context.Context) ([]byte, error) {
148 return exec.CommandContext(ctx,
149 "gofumpt", append([]string{"-w"}, godirs...)...,
150 ).CombinedOutput()
151 },
152 }, tool{
153 name: "go vet",
154 run: func(ctx context.Context) ([]byte, error) {
155 return exec.CommandContext(ctx,
156 "go", "vet", "./...",
157 ).CombinedOutput()
158 },
159 }, tool{
160 name: "staticcheck",
161 run: func(ctx context.Context) ([]byte, error) {
162 return exec.CommandContext(ctx,
163 "staticcheck", "./...",
164 ).CombinedOutput()
165 },
166 }, tool{
167 name: "guvulncheck",
168 run: func(ctx context.Context) ([]byte, error) {
169 return exec.CommandContext(ctx,
170 "govulncheck", "./...",
171 ).CombinedOutput()
172 },
173 }, tool{
174 name: "go build",
175 run: func(ctx context.Context) ([]byte, error) {
176 return exec.CommandContext(ctx,
177 "go", "build", "-o", "/dev/null", "./...",
178 ).CombinedOutput()
179 },
180 })
181 }
182 if len(tools) > 0 {
183 tools = append(tools, tool{
184 name: "git commit",
185 run: func(ctx context.Context) ([]byte, error) {
186 return exec.CommandContext(ctx,
187 "git", "add", ".",
188 ).CombinedOutput()
189 },
190 })
191 }
192 return tools, nil
193}