15
15
package main
16
16
17
17
import (
18
- "encoding/json"
19
- "errors"
20
- "fmt"
21
- "io"
22
18
"os"
23
- "slices"
24
19
25
- "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/root"
26
20
"github.com/spf13/cobra"
27
- "github.com/spf13/pflag"
28
- )
29
-
30
- var (
31
- errFlagDeleted = errors .New ("flag was deleted" )
32
- errFlagTypeChanged = errors .New ("flag type changed" )
33
- errFlagDefaultChanged = errors .New ("flag default value changed" )
34
- errCmdDeleted = errors .New ("command deleted" )
35
- errCmdRemovedAlias = errors .New ("command alias removed" )
36
- errFlagShortChanged = errors .New ("flag shorthand changed" )
37
21
)
38
22
39
23
type flagData struct {
@@ -47,151 +31,19 @@ type cmdData struct {
47
31
Flags map [string ]flagData `json:"flags"`
48
32
}
49
33
50
- func generateCmd (cmd * cobra.Command ) cmdData {
51
- data := cmdData {}
52
- if len (cmd .Aliases ) > 0 {
53
- data .Aliases = cmd .Aliases
54
- }
55
- flags := false
56
- data .Flags = map [string ]flagData {}
57
- cmd .Flags ().VisitAll (func (f * pflag.Flag ) {
58
- data .Flags [f .Name ] = flagData {
59
- Type : f .Value .Type (),
60
- Default : f .DefValue ,
61
- Short : f .Shorthand ,
62
- }
63
- flags = true
64
- })
65
- if ! flags {
66
- data .Flags = nil
67
- }
68
- return data
69
- }
70
-
71
- func generateCmds (cmd * cobra.Command ) map [string ]cmdData {
72
- data := map [string ]cmdData {}
73
- data [cmd .CommandPath ()] = generateCmd (cmd )
74
- for _ , c := range cmd .Commands () {
75
- for k , v := range generateCmds (c ) {
76
- data [k ] = v
77
- }
78
- }
79
- return data
80
- }
81
-
82
- func generateCmdRun (output io.Writer ) error {
83
- cliCmd := root .Builder ()
84
- data := generateCmds (cliCmd )
85
- return json .NewEncoder (output ).Encode (data )
86
- }
87
-
88
- func compareFlags (cmdPath string , mainFlags , changedFlags map [string ]flagData ) []error {
89
- if mainFlags == nil {
90
- return nil
91
- }
92
-
93
- changes := []error {}
94
-
95
- for flagName , flagValue := range mainFlags {
96
- changedFlagValue , ok := changedFlags [flagName ]
97
- if ! ok {
98
- changes = append (changes , fmt .Errorf ("%w: %s --%s" , errFlagDeleted , cmdPath , flagName ))
99
- continue
100
- }
101
-
102
- if flagValue .Type != changedFlagValue .Type {
103
- changes = append (changes , fmt .Errorf ("%w: %s --%s" , errFlagTypeChanged , cmdPath , flagName ))
104
- }
105
-
106
- if flagValue .Default != changedFlagValue .Default {
107
- changes = append (changes , fmt .Errorf ("%w: %s --%s" , errFlagDefaultChanged , cmdPath , flagName ))
108
- }
109
-
110
- if flagValue .Short != changedFlagValue .Short {
111
- changes = append (changes , fmt .Errorf ("%w: %s --%s" , errFlagShortChanged , cmdPath , flagName ))
112
- }
113
- }
114
-
115
- return changes
116
- }
117
-
118
- func compareCmds (changedData , mainData map [string ]cmdData ) error {
119
- changes := []error {}
120
- for cmdPath , mv := range mainData {
121
- cv , ok := changedData [cmdPath ]
122
- if ! ok {
123
- changes = append (changes , fmt .Errorf ("%w: %s" , errCmdDeleted , cmdPath ))
124
- continue
125
- }
126
-
127
- if mv .Aliases != nil {
128
- mainAliases := mv .Aliases
129
- changedAliases := cv .Aliases
130
-
131
- for _ , alias := range mainAliases {
132
- if ! slices .Contains (changedAliases , alias ) {
133
- changes = append (changes , fmt .Errorf ("%w: %s" , errCmdRemovedAlias , cmdPath ))
134
- }
135
- }
136
- }
137
-
138
- changes = append (changes , compareFlags (cmdPath , mv .Flags , cv .Flags )... )
139
- }
140
-
141
- if len (changes ) > 0 {
142
- return errors .Join (changes ... )
143
- }
144
-
145
- return nil
146
- }
147
-
148
- func validateCmdRun (output io.Writer , input io.Reader ) error {
149
- var inputData map [string ]cmdData
150
- if err := json .NewDecoder (input ).Decode (& inputData ); err != nil {
151
- return err
152
- }
153
-
154
- cliCmd := root .Builder ()
155
- generatedData := generateCmds (cliCmd )
156
-
157
- err := compareCmds (generatedData , inputData )
158
- if err != nil {
159
- return err
160
- }
161
-
162
- fmt .Fprintln (output , "no breaking changes detected" )
163
- return nil
164
- }
165
-
166
- func buildCmd () * cobra.Command {
167
- generateCmd := & cobra.Command {
168
- Use : "generate" ,
169
- Short : "Generate the CLI command structure." ,
170
- RunE : func (cmd * cobra.Command , _ []string ) error {
171
- return generateCmdRun (cmd .OutOrStdout ())
172
- },
173
- }
174
-
175
- validateCmd := & cobra.Command {
176
- Use : "validate" ,
177
- Short : "Validate the CLI command structure." ,
178
- RunE : func (cmd * cobra.Command , _ []string ) error {
179
- return validateCmdRun (cmd .OutOrStdout (), cmd .InOrStdin ())
180
- },
181
- }
182
-
34
+ func buildRootCmd () * cobra.Command {
183
35
rootCmd := & cobra.Command {
184
36
Use : "breakvalidator" ,
185
37
Short : "CLI tool to validate breaking changes in the CLI." ,
186
38
}
187
- rootCmd .AddCommand (generateCmd )
188
- rootCmd .AddCommand (validateCmd )
39
+ rootCmd .AddCommand (buildGenerateCmd () )
40
+ rootCmd .AddCommand (buildValidateCmd () )
189
41
190
42
return rootCmd
191
43
}
192
44
193
45
func main () {
194
- rootCmd := buildCmd ()
46
+ rootCmd := buildRootCmd ()
195
47
err := rootCmd .Execute ()
196
48
if err != nil {
197
49
os .Exit (1 )
0 commit comments