/ magefiles / mage.go
mage.go
  1  //go:build mage
  2  
  3  package main
  4  
  5  import (
  6  	"fmt"
  7  	"os"
  8  	"path/filepath"
  9  	"runtime"
 10  	"strings"
 11  	"time"
 12  	"unicode"
 13  
 14  	"github.com/magefile/mage/mg"
 15  	"github.com/magefile/mage/sh"
 16  )
 17  
 18  const (
 19  	projectName          = "enbas"
 20  	defaultAppName       = projectName
 21  	defaultInstallPrefix = "/usr/local"
 22  
 23  	envInstallPrefix    = "ENBAS_INSTALL_PREFIX"
 24  	envTestVerbose      = "ENBAS_TEST_VERBOSE"
 25  	envTestCover        = "ENBAS_TEST_COVER"
 26  	envBuildRebuildAll  = "ENBAS_BUILD_REBUILD_ALL"
 27  	envBuildVerbose     = "ENBAS_BUILD_VERBOSE"
 28  	envFailOnFormatting = "ENBAS_FAIL_ON_FORMATTING"
 29  	envAppName          = "ENBAS_APP_NAME"
 30  	envAppVersion       = "ENBAS_APP_VERSION"
 31  )
 32  
 33  var Default = Build
 34  
 35  // Test run the go tests.
 36  // To enable verbose mode set ENBAS_TEST_VERBOSE=1.
 37  // To enable coverage mode set ENBAS_TEST_COVER=1.
 38  func Test() error {
 39  	goTest := sh.RunCmd("go", "test")
 40  
 41  	args := []string{"./..."}
 42  
 43  	if os.Getenv(envTestVerbose) == "1" {
 44  		args = append(args, "-v")
 45  	}
 46  
 47  	if os.Getenv(envTestCover) == "1" {
 48  		args = append(args, "-cover")
 49  	}
 50  
 51  	return goTest(args...)
 52  }
 53  
 54  // Lint runs golangci-lint against the code.
 55  func Lint() error {
 56  	return sh.RunV("golangci-lint", "run", "--color", "always")
 57  }
 58  
 59  // Gosec runs gosec against the code.
 60  func Gosec() error {
 61  	return sh.RunV("gosec", "./...")
 62  }
 63  
 64  // Staticcheck runs staticcheck against the code.
 65  func Staticcheck() error {
 66  	return sh.RunV("staticcheck", "./...")
 67  }
 68  
 69  // Gofmt checks the code for formatting.
 70  // To fail on formatting set BEACON_FAIL_ON_FORMATTING=1
 71  func Gofmt() error {
 72  	output, err := sh.Output("go", "fmt", "./...")
 73  	if err != nil {
 74  		return err
 75  	}
 76  
 77  	formattedFiles := ""
 78  
 79  	for _, file := range strings.Split(output, "\n") {
 80  		formattedFiles += "\n- " + file
 81  	}
 82  
 83  	if os.Getenv(envFailOnFormatting) != "1" {
 84  		fmt.Println(formattedFiles)
 85  
 86  		return nil
 87  	}
 88  
 89  	if len(output) != 0 {
 90  		return fmt.Errorf("The following files needed to be formatted: %s", formattedFiles)
 91  	}
 92  
 93  	return nil
 94  }
 95  
 96  // Govet runs go vet against the code.
 97  func Govet() error {
 98  	return sh.RunV("go", "vet", "./...")
 99  }
100  
101  // Build build the executable.
102  // To rebuild packages that are already up-to-date set ENBAS_BUILD_REBUILD_ALL=1
103  // To enable verbose mode set ENBAS_BUILD_VERBOSE=1
104  func Build() error {
105  	fmt.Println("Building the binary...")
106  
107  	main := "./cmd/" + projectName
108  	flags := ldflags()
109  	build := sh.RunCmd("go", "build")
110  	args := []string{"-ldflags=" + flags, "-o", binary()}
111  
112  	if os.Getenv(envBuildRebuildAll) == "1" {
113  		args = append(args, "-a")
114  	}
115  
116  	if os.Getenv(envBuildVerbose) == "1" {
117  		args = append(args, "-v")
118  	}
119  
120  	args = append(args, main)
121  
122  	if err := build(args...); err != nil {
123  		return fmt.Errorf("error building the binary: %w", err)
124  	}
125  
126  	return nil
127  }
128  
129  // Install install the executable.
130  func Install() error {
131  	mg.Deps(Build)
132  
133  	installPrefix := os.Getenv(envInstallPrefix)
134  	app := appName()
135  	binary := binary()
136  
137  	if installPrefix == "" {
138  		installPrefix = defaultInstallPrefix
139  	}
140  
141  	dest := filepath.Join(installPrefix, "bin", app)
142  
143  	fmt.Println("Installing the binary to", dest)
144  
145  	if err := sh.Copy(dest, binary); err != nil {
146  		return fmt.Errorf("unable to install %s; %w", dest, err)
147  	}
148  
149  	fmt.Printf("Successfully installed %s to %s\n", projectName, dest)
150  
151  	return nil
152  }
153  
154  // Clean clean the workspace.
155  func Clean() error {
156  	fmt.Println("Cleaning the workspace...")
157  
158  	if err := sh.Rm(binary()); err != nil {
159  		return err
160  	}
161  
162  	if err := sh.Run("go", "clean", "./..."); err != nil {
163  		return err
164  	}
165  
166  	fmt.Println("Workspace cleaned.")
167  
168  	return nil
169  }
170  
171  // ldflags returns the build flags.
172  func ldflags() string {
173  	var (
174  		infoPackage              = "codeflow.dananglin.me.uk/apollo/enbas/internal/info"
175  		binaryVersionVar         = infoPackage + "." + "BinaryVersion"
176  		gitCommitVar             = infoPackage + "." + "GitCommit"
177  		goVersionVar             = infoPackage + "." + "GoVersion"
178  		buildTimeVar             = infoPackage + "." + "BuildTime"
179  		applicationNameVar       = infoPackage + "." + "ApplicationName"
180  		applicationTitledNameVar = infoPackage + "." + "ApplicationTitledName"
181  
182  		ldflagsfmt = "-s -w -X %s=%s -X %s=%s -X %s=%s -X %s=%s -X %s=%s -X %s=%s"
183  		buildTime  = time.Now().UTC().Format(time.RFC3339)
184  	)
185  
186  	return fmt.Sprintf(
187  		ldflagsfmt,
188  		binaryVersionVar, binaryVersion(),
189  		gitCommitVar, gitCommit(),
190  		goVersionVar, runtime.Version(),
191  		buildTimeVar, buildTime,
192  		applicationNameVar, appName(),
193  		applicationTitledNameVar, appTitledName(),
194  	)
195  }
196  
197  // binaryVersion returns the version of the binary.
198  // If ENBAS_APP_VERSION is set, the value of that is returned, otherwise
199  // the latest git tag (using git describe) is returned.
200  func binaryVersion() string {
201  	ver := os.Getenv(envAppVersion)
202  	if ver != "" {
203  		return ver
204  	}
205  
206  	ver, err := sh.Output("git", "describe", "--tags")
207  	if err != nil {
208  		fmt.Printf("WARNING: error getting the binary version: %v.\n", err)
209  		return "N/A"
210  	}
211  
212  	return ver
213  }
214  
215  // gitCommit returns the current git commit
216  func gitCommit() string {
217  	commit, err := sh.Output("git", "rev-parse", "--short", "HEAD")
218  	if err != nil {
219  		commit = "N/A"
220  	}
221  
222  	return commit
223  }
224  
225  // appName returns the application's name.
226  // The value of ENBAS_APP_NAME is return if the environment variable is set
227  // otherwise the default name is returned.
228  func appName() string {
229  	appName := os.Getenv(envAppName)
230  
231  	if appName == "" {
232  		return defaultAppName
233  	}
234  
235  	return appName
236  }
237  
238  func binary() string {
239  	return filepath.Join("./__build", appName())
240  }
241  
242  func appTitledName() string {
243  	runes := []rune(appName())
244  	runes[0] = unicode.ToUpper(runes[0])
245  
246  	return string(runes)
247  }