1
16
17 package mage
18
19 import (
20 "fmt"
21 "log"
22 "net/url"
23 "os"
24 "path"
25 "path/filepath"
26 "strings"
27
28 "github.com/blang/semver/v4"
29 "github.com/uwu-tools/magex/pkg"
30 "github.com/uwu-tools/magex/pkg/gopath"
31 "github.com/uwu-tools/magex/shx"
32
33 kpath "k8s.io/utils/path"
34 "sigs.k8s.io/release-utils/command"
35 "sigs.k8s.io/release-utils/env"
36 )
37
38 const (
39
40 defaultGolangCILintVersion = "v1.55.2"
41 golangciCmd = "golangci-lint"
42 golangciConfig = ".golangci.yml"
43 golangciURLBase = "https://raw.githubusercontent.com/golangci/golangci-lint"
44 defaultMinGoVersion = "1.20"
45 )
46
47
48 func EnsureGolangCILint(version string, forceInstall bool) error {
49 found, err := pkg.IsCommandAvailable(golangciCmd, "--version", version)
50 if err != nil {
51 return fmt.Errorf(
52 "checking if %s is available: %w",
53 golangciCmd, err,
54 )
55 }
56
57 if !found || forceInstall {
58 if version == "" {
59 log.Printf(
60 "A golangci-lint version to install was not specified. Using default version: %s",
61 defaultGolangCILintVersion,
62 )
63
64 version = defaultGolangCILintVersion
65 }
66
67 if !strings.HasPrefix(version, "v") {
68 return fmt.Errorf(
69 "golangci-lint version (%s) must begin with a 'v'",
70 version,
71 )
72 }
73
74 if _, err := semver.ParseTolerant(version); err != nil {
75 return fmt.Errorf(
76 "%s was not SemVer-compliant. Cannot continue.: %w",
77 version, err,
78 )
79 }
80
81 installURL, err := url.Parse(golangciURLBase)
82 if err != nil {
83 return fmt.Errorf("parsing URL: %w", err)
84 }
85
86 installURL.Path = path.Join(installURL.Path, version, "install.sh")
87
88 err = gopath.EnsureGopathBin()
89 if err != nil {
90 return fmt.Errorf("ensuring $GOPATH/bin: %w", err)
91 }
92
93 gopathBin := gopath.GetGopathBin()
94
95 installCmd := command.New(
96 "curl",
97 "-sSfL",
98 installURL.String(),
99 ).Pipe(
100 "sh",
101 "-s",
102 "--",
103 "-b",
104 gopathBin,
105 version,
106 )
107
108 err = installCmd.RunSuccess()
109 if err != nil {
110 return fmt.Errorf("installing golangci-lint: %w", err)
111 }
112 }
113
114 return nil
115 }
116
117
118 func RunGolangCILint(version string, forceInstall bool, args ...string) error {
119 if _, err := kpath.Exists(kpath.CheckSymlinkOnly, golangciConfig); err != nil {
120 return fmt.Errorf(
121 "checking if golangci-lint config file (%s) exists: %w",
122 golangciConfig, err,
123 )
124 }
125
126 if err := EnsureGolangCILint(version, forceInstall); err != nil {
127 return fmt.Errorf("ensuring golangci-lint is installed: %w", err)
128 }
129
130 if err := shx.RunV(golangciCmd, "version"); err != nil {
131 return fmt.Errorf("getting golangci-lint version: %w", err)
132 }
133
134 if err := shx.RunV(golangciCmd, "linters"); err != nil {
135 return fmt.Errorf("listing golangci-lint linters: %w", err)
136 }
137
138 runArgs := []string{"run"}
139 runArgs = append(runArgs, args...)
140
141 if err := shx.RunV(golangciCmd, runArgs...); err != nil {
142 return fmt.Errorf("running golangci-lint linters: %w", err)
143 }
144
145 return nil
146 }
147
148 func TestGo(verbose bool, pkgs ...string) error {
149 return testGo(verbose, "", pkgs...)
150 }
151
152 func TestGoWithTags(verbose bool, tags string, pkgs ...string) error {
153 return testGo(verbose, tags, pkgs...)
154 }
155
156 func testGo(verbose bool, tags string, pkgs ...string) error {
157 verboseFlag := ""
158 if verbose {
159 verboseFlag = "-v"
160 }
161
162 pkgArgs := []string{}
163 if len(pkgs) > 0 {
164 for _, p := range pkgs {
165 pkgArg := fmt.Sprintf("./%s/...", p)
166 pkgArgs = append(pkgArgs, pkgArg)
167 }
168 } else {
169 pkgArgs = []string{"./..."}
170 }
171
172 cmdArgs := []string{"test"}
173 cmdArgs = append(cmdArgs, verboseFlag)
174 if tags != "" {
175 cmdArgs = append(cmdArgs, "-tags", tags)
176 }
177 cmdArgs = append(cmdArgs, pkgArgs...)
178
179 if err := shx.RunV(
180 "go",
181 cmdArgs...,
182 ); err != nil {
183 return fmt.Errorf("running go test: %w", err)
184 }
185
186 return nil
187 }
188
189
190
191 func VerifyGoMod() error {
192 minGoVersion := env.Default("MIN_GO_VERSION", defaultMinGoVersion)
193 if err := shx.RunV(
194 "go", "mod", "tidy", fmt.Sprintf("-compat=%s", minGoVersion),
195 ); err != nil {
196 return fmt.Errorf("running go mod tidy: %w", err)
197 }
198
199 if err := shx.RunV("git", "diff", "--exit-code", "go.*"); err != nil {
200 return fmt.Errorf("running go mod tidy: %w", err)
201 }
202
203 return nil
204 }
205
206
207 func VerifyBuild(scriptDir string) error {
208 wd, err := os.Getwd()
209 if err != nil {
210 return fmt.Errorf("getting working directory: %w", err)
211 }
212
213 scriptDir = filepath.Join(wd, scriptDir)
214
215 buildScript := filepath.Join(scriptDir, "verify-build.sh")
216 if err := shx.RunV(buildScript); err != nil {
217 return fmt.Errorf("running go build: %w", err)
218 }
219
220 return nil
221 }
222
View as plain text