Skip to content

Commit

Permalink
Merge pull request #121 from commitdev/117-add-check-command
Browse files Browse the repository at this point in the history
Added command to check your local installs.
  • Loading branch information
Direside committed May 22, 2020
2 parents f146c26 + 0be16e7 commit 5176cd0
Show file tree
Hide file tree
Showing 3 changed files with 194 additions and 0 deletions.
192 changes: 192 additions & 0 deletions cmd/check.go
@@ -0,0 +1,192 @@
package cmd

import (
"fmt"
"os"
"os/exec"
"regexp"
"strings"
"text/tabwriter"

"github.com/coreos/go-semver/semver"
"github.com/spf13/cobra"
)

func init() {
rootCmd.AddCommand(checkCmd)
}

type requirement struct {
name string
command string
args []string
minVersion string
regexStr string
docsURL string
}

type versionError struct {
errorText string
}

type commandError struct {
Command string
ErrorText string
Suggestion string
}

func (e *versionError) Error() string {
return fmt.Sprintf("%s", e.errorText)
}

func (e *commandError) Error() string {
return fmt.Sprintf("%s", e.ErrorText)
}

func printErrors(errors []commandError) {
// initialize tabwriter
w := new(tabwriter.Writer)

// minwidth, tabwidth, padding, padchar, flags
w.Init(os.Stdout, 10, 12, 2, ' ', 0)

defer w.Flush()

fmt.Fprintf(w, "\n %s\t%s\t%s\t", "Command", "Error", "Info")
fmt.Fprintf(w, "\n %s\t%s\t%s\t", "---------", "---------", "---------")

for _, e := range errors {
fmt.Fprintf(w, "\n%s\t%s\t%s\t", e.Command, e.ErrorText, e.Suggestion)
}
}

// getSemver uses the regular expression from the requirement to parse the
// output of a command and extract the version from it. Returns the version
// or an error if the version string could not be parsed.
func getSemver(req requirement, out []byte) (*semver.Version, error) {
re := regexp.MustCompile(req.regexStr)
v := re.FindStringSubmatch(string(out))
if len(v) < 4 {
return nil, &commandError{
req.command,
"Could not find version number in output",
fmt.Sprintf("Try running %s %s locally and checking it works.", req.command, strings.Join(req.args, " ")),
}
}
versionString := fmt.Sprintf("%s.%s.%s", v[1], v[2], v[3])
version, err := semver.NewVersion(versionString)
if err != nil {
return version, err
}
return version, nil
}

// checkSemver validates that the version of a tool meets the minimum required
// version listed in your requirement. Returns a boolean.
// For more information on parsing semver, see semver.org
// If your tool doesn't do full semver then you may need to add custom logic
// to support it.
func checkSemver(req requirement, actualVersion *semver.Version) bool {
requiredVersion := semver.New(req.minVersion)
return actualVersion.LessThan(*requiredVersion)
}

var checkCmd = &cobra.Command{
Use: "check",
Short: "Print the check number of commit0",
Run: func(cmd *cobra.Command, args []string) {
// Add any new requirements to this slice.
required := []requirement{
{
name: "AWS CLI\t\t",
command: "aws",
args: []string{"--version"},
regexStr: `aws-cli\/(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)`,
minVersion: "1.16.0",
docsURL: "https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html",
},
{
name: "Kubectl\t\t",
command: "kubectl",
args: []string{"version", "--client=true", "--short"},
regexStr: `Client Version: v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)`,
minVersion: "1.15.2",
docsURL: "https://kubernetes.io/docs/tasks/tools/install-kubectl/",
},
{
name: "Terraform\t",
command: "terraform",
args: []string{"version"},
regexStr: `Terraform v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)`,
minVersion: "0.12.0",
docsURL: "https://www.terraform.io/downloads.html",
},
{
name: "jq\t\t",
command: "jq",
args: []string{"--version"},
regexStr: `jq-(0|[1-9]\d*)\.(0|[1-9]\d*)-(0|[1-9]\d*)`,
minVersion: "1.5.0",
docsURL: "https://stedolan.github.io/jq/download/",
},
{
name: "Git\t\t",
command: "git",
args: []string{"version"},
regexStr: `^git version (0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)`,
minVersion: "2.17.1",
docsURL: "https://git-scm.com/book/en/v2/Getting-Started-Installing-Git",
},
}

// Store and errors from the commands we run.
errors := []commandError{}

fmt.Println("Checking Zero Requirements...")
for _, r := range required {
fmt.Printf("%s", r.name)
// In future we could parse the stderr and stdout separately, but for now it's nice to see
// the full output on a failure.
out, err := exec.Command(r.command, r.args...).CombinedOutput()
if err != nil {
cerr := commandError{
fmt.Sprintf("%s %s", r.command, strings.Join(r.args, " ")),
err.Error(),
r.docsURL,
}
errors = append(errors, cerr)
fmt.Printf("\033[0;31mFAIL\033[0m\t\t%s\n", "-")
continue
}
version, err := getSemver(r, out)
if err != nil {
cerr := commandError{
r.command,
err.Error(),
r.docsURL,
}
errors = append(errors, cerr)
fmt.Printf("\033[0;31mFAIL\033[0m\t\t%s\n", version)
continue
}
if checkSemver(r, version) {
cerr := commandError{
r.command,
fmt.Sprintf("Version does not meet required. Want: %s; Got: %s", r.minVersion, version),
r.docsURL,
}
errors = append(errors, cerr)
fmt.Printf("\033[0;31mFAIL\033[0m\t\t%s\n", version)
} else {
fmt.Printf("\033[0;32mPASS\033[0m\t\t%s\n", version)
}
}

if len(errors) > 0 {
printErrors(errors)
os.Exit(1)
}

fmt.Println()
},
}
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -7,6 +7,7 @@ require (
github.com/chzyer/logex v1.1.10 // indirect
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect
github.com/coreos/go-semver v0.2.0
github.com/google/uuid v1.1.1
github.com/gorilla/handlers v1.4.2
github.com/gorilla/mux v1.7.3
Expand Down
1 change: 1 addition & 0 deletions go.sum
Expand Up @@ -26,6 +26,7 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand Down

0 comments on commit 5176cd0

Please sign in to comment.