@@ -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
1919type 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
2728type 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+
6294var 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
0 commit comments