Skip to content

Commit 0be16e7

Browse files
committed
Switched to using semver instead of custom checker functions.
1 parent e2b83f4 commit 0be16e7

File tree

3 files changed

+85
-145
lines changed

3 files changed

+85
-145
lines changed

cmd/check.go

Lines changed: 83 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import (
55
"os"
66
"os/exec"
77
"regexp"
8-
"strconv"
98
"strings"
109
"text/tabwriter"
1110

11+
"github.com/coreos/go-semver/semver"
1212
"github.com/spf13/cobra"
1313
)
1414

@@ -17,11 +17,12 @@ func init() {
1717
}
1818

1919
type requirement struct {
20-
name string
21-
command string
22-
args []string
23-
docsURL string
24-
checker func([]byte) (string, error)
20+
name string
21+
command string
22+
args []string
23+
minVersion string
24+
regexStr string
25+
docsURL string
2526
}
2627

2728
type versionError struct {
@@ -59,156 +60,83 @@ func printErrors(errors []commandError) {
5960
}
6061
}
6162

63+
// getSemver uses the regular expression from the requirement to parse the
64+
// output of a command and extract the version from it. Returns the version
65+
// or an error if the version string could not be parsed.
66+
func getSemver(req requirement, out []byte) (*semver.Version, error) {
67+
re := regexp.MustCompile(req.regexStr)
68+
v := re.FindStringSubmatch(string(out))
69+
if len(v) < 4 {
70+
return nil, &commandError{
71+
req.command,
72+
"Could not find version number in output",
73+
fmt.Sprintf("Try running %s %s locally and checking it works.", req.command, strings.Join(req.args, " ")),
74+
}
75+
}
76+
versionString := fmt.Sprintf("%s.%s.%s", v[1], v[2], v[3])
77+
version, err := semver.NewVersion(versionString)
78+
if err != nil {
79+
return version, err
80+
}
81+
return version, nil
82+
}
83+
84+
// checkSemver validates that the version of a tool meets the minimum required
85+
// version listed in your requirement. Returns a boolean.
86+
// For more information on parsing semver, see semver.org
87+
// If your tool doesn't do full semver then you may need to add custom logic
88+
// to support it.
89+
func checkSemver(req requirement, actualVersion *semver.Version) bool {
90+
requiredVersion := semver.New(req.minVersion)
91+
return actualVersion.LessThan(*requiredVersion)
92+
}
93+
6294
var checkCmd = &cobra.Command{
6395
Use: "check",
6496
Short: "Print the check number of commit0",
6597
Run: func(cmd *cobra.Command, args []string) {
6698
// Add any new requirements to this slice.
6799
required := []requirement{
68100
{
69-
name: "AWS CLI\t\t",
70-
command: "aws",
71-
args: []string{"--version"},
72-
docsURL: "",
73-
checker: func(output []byte) (string, error) {
74-
ver := ""
75-
re := regexp.MustCompile(`aws-cli/([0-9]+)\.([0-9]+)\.([0-9]+)`)
76-
m := re.FindStringSubmatch(string(output))
77-
major, err := strconv.ParseInt(m[1], 0, 64)
78-
if err != nil {
79-
return ver, err
80-
}
81-
minor, err := strconv.ParseInt(m[2], 0, 64)
82-
if err != nil {
83-
return ver, err
84-
}
85-
patch, err := strconv.ParseInt(m[3], 0, 64)
86-
if err != nil {
87-
return ver, err
88-
}
89-
90-
ver = fmt.Sprintf("%d.%d.%d", major, minor, patch)
91-
92-
if major < 1 || (major == 1 && minor < 16) {
93-
return ver, &versionError{"Requires 1.16 or greater."}
94-
}
95-
96-
return ver, err
97-
}},
101+
name: "AWS CLI\t\t",
102+
command: "aws",
103+
args: []string{"--version"},
104+
regexStr: `aws-cli\/(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)`,
105+
minVersion: "1.16.0",
106+
docsURL: "https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html",
107+
},
98108
{
99-
name: "Kubectl\t\t",
100-
command: "kubectl",
101-
args: []string{"version", "--client=true"},
102-
docsURL: "https://kubernetes.io/docs/tasks/tools/install-kubectl/",
103-
checker: func(output []byte) (string, error) {
104-
ver := ""
105-
re := regexp.MustCompile(`version\.Info{Major:"([0-9]+)", Minor:"([0-9]+)"`)
106-
m := re.FindStringSubmatch(string(output))
107-
major, err := strconv.ParseInt(m[1], 0, 64)
108-
if err != nil {
109-
return ver, err
110-
}
111-
minor, err := strconv.ParseInt(m[2], 0, 64)
112-
if err != nil {
113-
return ver, err
114-
}
115-
116-
ver = fmt.Sprintf("%d.%d", major, minor)
117-
118-
if major < 1 || (major == 1 && minor < 12) {
119-
return ver, &versionError{"Requires 2.12 or greater."}
120-
}
121-
122-
return ver, err
123-
},
109+
name: "Kubectl\t\t",
110+
command: "kubectl",
111+
args: []string{"version", "--client=true", "--short"},
112+
regexStr: `Client Version: v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)`,
113+
minVersion: "1.15.2",
114+
docsURL: "https://kubernetes.io/docs/tasks/tools/install-kubectl/",
124115
},
125116
{
126-
name: "Terraform\t",
127-
command: "terraform",
128-
args: []string{"version"},
129-
docsURL: "https://www.terraform.io/downloads.html",
130-
checker: func(output []byte) (string, error) {
131-
ver := ""
132-
re := regexp.MustCompile(`Terraform v([0-9]+)\.([0-9]+)\.([0-9]+)`)
133-
m := re.FindStringSubmatch(string(output))
134-
major, err := strconv.ParseInt(m[1], 0, 64)
135-
if err != nil {
136-
return ver, err
137-
}
138-
minor, err := strconv.ParseInt(m[2], 0, 64)
139-
if err != nil {
140-
return ver, err
141-
}
142-
patch, err := strconv.ParseInt(m[3], 0, 64)
143-
if err != nil {
144-
return ver, err
145-
}
146-
147-
ver = fmt.Sprintf("%d.%d.%d", major, minor, patch)
148-
149-
if major < 0 || (major == 0 && minor < 12) {
150-
return ver, &versionError{"Zero requires terraform 0.12 or greater."}
151-
}
152-
153-
return ver, err
154-
},
117+
name: "Terraform\t",
118+
command: "terraform",
119+
args: []string{"version"},
120+
regexStr: `Terraform v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)`,
121+
minVersion: "0.12.0",
122+
docsURL: "https://www.terraform.io/downloads.html",
155123
},
156124
{
157-
name: "jq\t\t",
158-
command: "jq",
159-
args: []string{"--version"},
160-
docsURL: "https://stedolan.github.io/jq/download/",
161-
checker: func(output []byte) (string, error) {
162-
ver := ""
163-
re := regexp.MustCompile(`jq-([0-9]+)\.([0-9]+)-`)
164-
m := re.FindStringSubmatch(string(output))
165-
major, err := strconv.ParseInt(m[1], 0, 64)
166-
if err != nil {
167-
return ver, err
168-
}
169-
minor, err := strconv.ParseInt(m[2], 0, 64)
170-
if err != nil {
171-
return ver, err
172-
}
173-
174-
ver = fmt.Sprintf("%d.%d", major, minor)
175-
176-
if major < 1 || (major == 1 && minor < 5) {
177-
return ver, &versionError{"Requires jq version 1.15 or greater."}
178-
}
179-
180-
return ver, err
181-
}},
125+
name: "jq\t\t",
126+
command: "jq",
127+
args: []string{"--version"},
128+
regexStr: `jq-(0|[1-9]\d*)\.(0|[1-9]\d*)-(0|[1-9]\d*)`,
129+
minVersion: "1.5.0",
130+
docsURL: "https://stedolan.github.io/jq/download/",
131+
},
182132
{
183-
name: "Git\t\t",
184-
command: "git",
185-
args: []string{"version"},
186-
docsURL: "https://git-scm.com/book/en/v2/Getting-Started-Installing-Git",
187-
checker: func(output []byte) (string, error) {
188-
ver := ""
189-
re := regexp.MustCompile(`git version ([0-9]+)\.([0-9]+)\.([0-9]+)`)
190-
m := re.FindStringSubmatch(string(output))
191-
major, err := strconv.ParseInt(m[1], 0, 64)
192-
if err != nil {
193-
return ver, err
194-
}
195-
minor, err := strconv.ParseInt(m[2], 0, 64)
196-
if err != nil {
197-
return ver, err
198-
}
199-
patch, err := strconv.ParseInt(m[3], 0, 64)
200-
if err != nil {
201-
return ver, err
202-
}
203-
204-
ver = fmt.Sprintf("%d.%d.%d", major, minor, patch)
205-
206-
if major < 2 || (major == 2 && minor < 12) {
207-
return ver, &versionError{"Zero requires git version 2.12 or greater."}
208-
}
209-
210-
return ver, err
211-
}},
133+
name: "Git\t\t",
134+
command: "git",
135+
args: []string{"version"},
136+
regexStr: `^git version (0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)`,
137+
minVersion: "2.17.1",
138+
docsURL: "https://git-scm.com/book/en/v2/Getting-Started-Installing-Git",
139+
},
212140
}
213141

214142
// Store and errors from the commands we run.
@@ -230,7 +158,7 @@ var checkCmd = &cobra.Command{
230158
fmt.Printf("\033[0;31mFAIL\033[0m\t\t%s\n", "-")
231159
continue
232160
}
233-
version, err := r.checker(out)
161+
version, err := getSemver(r, out)
234162
if err != nil {
235163
cerr := commandError{
236164
r.command,
@@ -239,13 +167,23 @@ var checkCmd = &cobra.Command{
239167
}
240168
errors = append(errors, cerr)
241169
fmt.Printf("\033[0;31mFAIL\033[0m\t\t%s\n", version)
170+
continue
171+
}
172+
if checkSemver(r, version) {
173+
cerr := commandError{
174+
r.command,
175+
fmt.Sprintf("Version does not meet required. Want: %s; Got: %s", r.minVersion, version),
176+
r.docsURL,
177+
}
178+
errors = append(errors, cerr)
179+
fmt.Printf("\033[0;31mFAIL\033[0m\t\t%s\n", version)
242180
} else {
243181
fmt.Printf("\033[0;32mPASS\033[0m\t\t%s\n", version)
244182
}
245183
}
246184

247185
if len(errors) > 0 {
248-
printErrors((errors))
186+
printErrors(errors)
249187
os.Exit(1)
250188
}
251189

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
github.com/chzyer/logex v1.1.10 // indirect
88
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
99
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect
10+
github.com/coreos/go-semver v0.2.0
1011
github.com/google/uuid v1.1.1
1112
github.com/gorilla/handlers v1.4.2
1213
github.com/gorilla/mux v1.7.3

go.sum

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
2626
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
2727
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
2828
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
29+
github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY=
2930
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
3031
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
3132
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

0 commit comments

Comments
 (0)