From ae7e1711fd2c8e10fde779700088f532dc12d62b Mon Sep 17 00:00:00 2001
From: Charlie Moog <moogcharlie@gmail.com>
Date: Thu, 22 Oct 2020 10:43:19 -0500
Subject: [PATCH] Add golintci and fix errors

---
 .github/workflows/test.yaml     | 15 +++++----------
 .golangci.yml                   | 17 +++++++++++++++++
 ci/image/Dockerfile             |  3 +--
 ci/steps/lint.sh                |  7 +++++--
 internal/clog/error.go          | 12 ++++++------
 internal/cmd/auth.go            |  2 +-
 internal/cmd/ceapi.go           | 11 +----------
 internal/cmd/envs.go            | 10 +++++-----
 internal/cmd/login.go           |  2 +-
 internal/cmd/rebuild.go         |  3 +--
 internal/cmd/resourcemanager.go |  4 +++-
 internal/cmd/shell.go           |  2 +-
 12 files changed, 47 insertions(+), 41 deletions(-)
 create mode 100644 .golangci.yml

diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index 996a13a1..81c7a10d 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -19,17 +19,12 @@ jobs:
   lint:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v1
-      - uses: actions/cache@v1
-        with:
-          path: ~/go/pkg/mod
-          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
-          restore-keys: |
-            ${{ runner.os }}-go-
-      - name: lint
-        uses: ./ci/image
+      - uses: actions/checkout@v2
+      - name: golangci-lint
+        uses: golangci/golangci-lint-action@v2
         with:
-          args: ./ci/steps/lint.sh
+          # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
+          version: v1.29
   test:
     runs-on: ubuntu-latest
     steps:
diff --git a/.golangci.yml b/.golangci.yml
new file mode 100644
index 00000000..aa56dabb
--- /dev/null
+++ b/.golangci.yml
@@ -0,0 +1,17 @@
+# See https://golangci-lint.run/usage/configuration/
+linters-settings:
+  goconst:
+    min-len: 4 
+    min-occurrences: 3
+  gocognit:
+    min-complexity: 46
+  nestif:
+    min-complexity: 10
+  golint:
+  govet:
+    settings:
+      printf:
+        funcs: # Run `go tool vet help printf` to see available settings for `printf` analyzer.
+          - (cdr.dev/coder-cli/internal/clog).Tipf
+          - (cdr.dev/coder-cli/internal/clog).Hintf
+          - (cdr.dev/coder-cli/internal/clog).Causef
\ No newline at end of file
diff --git a/ci/image/Dockerfile b/ci/image/Dockerfile
index cb06bf81..8eb77371 100644
--- a/ci/image/Dockerfile
+++ b/ci/image/Dockerfile
@@ -4,5 +4,4 @@ ENV GOFLAGS="-mod=readonly"
 ENV CI=true
 
 RUN go get golang.org/x/tools/cmd/goimports
-RUN go get golang.org/x/lint/golint
-RUN go get github.com/mattn/goveralls
\ No newline at end of file
+RUN go get github.com/mattn/goveralls
diff --git a/ci/steps/lint.sh b/ci/steps/lint.sh
index c3f72614..dcb2acaa 100755
--- a/ci/steps/lint.sh
+++ b/ci/steps/lint.sh
@@ -4,5 +4,8 @@ set -euo pipefail
 
 echo "Linting..."
 
-go vet ./...
-golint -set_exit_status ./...
+cd "$(dirname "$0")"
+cd ../../
+
+echo "--- golangci-lint"
+golangci-lint run -c .golangci.yml
diff --git a/internal/clog/error.go b/internal/clog/error.go
index 71183573..66d28ec1 100644
--- a/internal/clog/error.go
+++ b/internal/clog/error.go
@@ -112,18 +112,18 @@ func Bold(a string) string {
 	return color.New(color.Bold).Sprint(a)
 }
 
-// Tip formats according to the given format specifier and prepends a bolded "tip: " header.
-func Tip(format string, a ...interface{}) string {
+// Tipf formats according to the given format specifier and prepends a bolded "tip: " header.
+func Tipf(format string, a ...interface{}) string {
 	return fmt.Sprintf("%s %s", Bold("tip:"), fmt.Sprintf(format, a...))
 }
 
-// Hint formats according to the given format specifier and prepends a bolded "hint: " header.
-func Hint(format string, a ...interface{}) string {
+// Hintf formats according to the given format specifier and prepends a bolded "hint: " header.
+func Hintf(format string, a ...interface{}) string {
 	return fmt.Sprintf("%s %s", Bold("hint:"), fmt.Sprintf(format, a...))
 }
 
-// Cause formats according to the given format specifier and prepends a bolded "cause: " header.
-func Cause(format string, a ...interface{}) string {
+// Causef formats according to the given format specifier and prepends a bolded "cause: " header.
+func Causef(format string, a ...interface{}) string {
 	return fmt.Sprintf("%s %s", Bold("cause:"), fmt.Sprintf(format, a...))
 }
 
diff --git a/internal/cmd/auth.go b/internal/cmd/auth.go
index ff789ca3..b0105ac4 100644
--- a/internal/cmd/auth.go
+++ b/internal/cmd/auth.go
@@ -14,7 +14,7 @@ import (
 
 var errNeedLogin = clog.Fatal(
 	"failed to read session credentials",
-	clog.Hint(`did you run "coder login [https://coder.domain.com]"?`),
+	clog.Hintf(`did you run "coder login [https://coder.domain.com]"?`),
 )
 
 func newClient() (*coder.Client, error) {
diff --git a/internal/cmd/ceapi.go b/internal/cmd/ceapi.go
index f9b4ebe6..5c6297ad 100644
--- a/internal/cmd/ceapi.go
+++ b/internal/cmd/ceapi.go
@@ -78,15 +78,6 @@ func findEnv(ctx context.Context, client *coder.Client, envName, userEmail strin
 		"failed to find environment",
 		fmt.Sprintf("environment %q not found in %q", envName, found),
 		clog.BlankLine,
-		clog.Tip("run \"coder envs ls\" to view your environments"),
+		clog.Tipf("run \"coder envs ls\" to view your environments"),
 	)
 }
-
-type notFoundButDidFind struct {
-	needle   string
-	haystack []string
-}
-
-func (n notFoundButDidFind) Error() string {
-	return fmt.Sprintf("\"%s\" not found in %q: %v", n.needle, n.haystack, coder.ErrNotFound)
-}
diff --git a/internal/cmd/envs.go b/internal/cmd/envs.go
index f5c6d84c..6aea5afa 100644
--- a/internal/cmd/envs.go
+++ b/internal/cmd/envs.go
@@ -117,8 +117,8 @@ coder envs --user charlie@coder.com ls -o json \
 					if err = client.StopEnvironment(cmd.Context(), env.ID); err != nil {
 						atomic.AddInt32(&fails, 1)
 						err = clog.Fatal(fmt.Sprintf("stop environment %q", env.Name),
-							clog.Cause(err.Error()), clog.BlankLine,
-							clog.Hint("current environment status is %q", env.LatestStat.ContainerStatus),
+							clog.Causef(err.Error()), clog.BlankLine,
+							clog.Hintf("current environment status is %q", env.LatestStat.ContainerStatus),
 						)
 						clog.Log(err)
 						return err
@@ -186,7 +186,7 @@ coder envs create --cpu 4 --disk 100 --memory 8 --image 5f443b16-30652892427b955
 			clog.LogSuccess(
 				"creating environment...",
 				clog.BlankLine,
-				clog.Tip(`run "coder envs watch-build %q" to trail the build logs`, args[0]),
+				clog.Tipf(`run "coder envs watch-build %q" to trail the build logs`, args[0]),
 			)
 
 			if follow {
@@ -205,7 +205,7 @@ coder envs create --cpu 4 --disk 100 --memory 8 --image 5f443b16-30652892427b955
 	cmd.Flags().IntP("gpus", "g", defaultGPUs, "number GPUs an environment should be provisioned with.")
 	cmd.Flags().StringVarP(&img, "image", "i", "", "ID of the image to base the environment off of.")
 	cmd.Flags().BoolVar(&follow, "follow", false, "follow buildlog after initiating rebuild")
-	cmd.MarkFlagRequired("image")
+	_ = cmd.MarkFlagRequired("image")
 	return cmd
 }
 
@@ -296,7 +296,7 @@ coder envs edit back-end-env --disk 20`,
 			clog.LogSuccess(
 				"applied changes to the environment, rebuilding...",
 				clog.BlankLine,
-				clog.Tip(`run "coder envs watch-build %q" to trail the build logs`, envName),
+				clog.Tipf(`run "coder envs watch-build %q" to trail the build logs`, envName),
 			)
 			return nil
 		},
diff --git a/internal/cmd/login.go b/internal/cmd/login.go
index fdcbe765..2984822b 100644
--- a/internal/cmd/login.go
+++ b/internal/cmd/login.go
@@ -40,7 +40,7 @@ func makeLoginCmd() *cobra.Command {
 			// Don't return errors as it would print the usage.
 
 			if err := login(cmd, u, config.URL, config.Session); err != nil {
-				return xerrors.Errorf("Login error", err)
+				return xerrors.Errorf("login error: %w", err)
 			}
 			return nil
 		},
diff --git a/internal/cmd/rebuild.go b/internal/cmd/rebuild.go
index 41f3913d..8e6de326 100644
--- a/internal/cmd/rebuild.go
+++ b/internal/cmd/rebuild.go
@@ -58,7 +58,7 @@ coder envs rebuild backend-env --force`,
 			} else {
 				clog.LogSuccess(
 					"successfully started rebuild",
-					clog.Tip("run \"coder envs watch-build %s\" to follow the build logs", env.Name),
+					clog.Tipf("run \"coder envs watch-build %s\" to follow the build logs", env.Name),
 				)
 			}
 			return nil
@@ -75,7 +75,6 @@ coder envs rebuild backend-env --force`,
 func trailBuildLogs(ctx context.Context, client *coder.Client, envID string) error {
 	const check = "✅"
 	const failure = "❌"
-	const loading = "⌛"
 
 	newSpinner := func() *spinner.Spinner { return spinner.New(spinner.CharSets[11], 100*time.Millisecond) }
 
diff --git a/internal/cmd/resourcemanager.go b/internal/cmd/resourcemanager.go
index d4ee20bb..515318fc 100644
--- a/internal/cmd/resourcemanager.go
+++ b/internal/cmd/resourcemanager.go
@@ -214,7 +214,7 @@ func printResourceTop(writer io.Writer, groups []groupable, labeler envLabeler,
 	if len(userResources) == 0 {
 		clog.LogInfo(
 			"no groups for the given filters exist with active environments",
-			clog.Tip("run \"--show-empty\" to see groups with no resources."),
+			clog.Tipf("run \"--show-empty\" to see groups with no resources."),
 		)
 	}
 	return nil
@@ -318,6 +318,7 @@ func (a resources) String() string {
 	// )
 }
 
+//nolint:unused
 func (a resources) cpuUtilPercentage() string {
 	if a.cpuAllocation == 0 {
 		return "N/A"
@@ -325,6 +326,7 @@ func (a resources) cpuUtilPercentage() string {
 	return fmt.Sprintf("%.1f%%", a.cpuUtilization/a.cpuAllocation*100)
 }
 
+//nolint:unused
 func (a resources) memUtilPercentage() string {
 	if a.memAllocation == 0 {
 		return "N/A"
diff --git a/internal/cmd/shell.go b/internal/cmd/shell.go
index 9903058a..18197570 100644
--- a/internal/cmd/shell.go
+++ b/internal/cmd/shell.go
@@ -201,7 +201,7 @@ func networkErr(client *coder.Client, env *coder.Environment) error {
 			fmt.Sprintf("environment %q is not running", env.Name),
 			fmt.Sprintf("its current status is %q", env.LatestStat.ContainerStatus),
 			clog.BlankLine,
-			clog.Tip("run \"coder envs rebuild %s --follow\" to start the environment", env.Name),
+			clog.Tipf("run \"coder envs rebuild %s --follow\" to start the environment", env.Name),
 		)
 	}
 	return xerrors.Errorf("network error, is %q online?", env.Name)
