-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathvalidate.go
More file actions
201 lines (175 loc) · 5.65 KB
/
Copy pathvalidate.go
File metadata and controls
201 lines (175 loc) · 5.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
package validate
import (
"context"
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"github.com/deepsourcelabs/cli/config"
"github.com/deepsourcelabs/cli/configvalidator"
"github.com/deepsourcelabs/cli/deepsource"
"github.com/deepsourcelabs/cli/utils"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
)
// Options holds the metadata.
type Options struct{}
// NewCmdValidate handles the validation of the DeepSource config (.deepsource.toml)
// Internally it uses the package `configvalidator` to validate the config
func NewCmdValidate() *cobra.Command {
o := Options{}
cmd := &cobra.Command{
Use: "validate",
Short: "Validate DeepSource config",
Args: utils.NoArgs,
RunE: func(_ *cobra.Command, args []string) error {
return o.Run()
},
}
return cmd
}
// Run executes the command.
func (o *Options) Run() error {
// Fetch config
cfg, err := config.GetConfig()
if err != nil {
return fmt.Errorf("Error while reading DeepSource CLI config : %v", err)
}
err = cfg.VerifyAuthentication()
if err != nil {
return err
}
// Just an info
pterm.Info.Println("DeepSource config (.deepsource.toml) is mostly present in the root directory of the project.")
fmt.Println()
// Extract the path of DeepSource config
configPath, err := extractDSConfigPath()
if err != nil {
return err
}
// Read the config in the form of string and send it
content, err := ioutil.ReadFile(configPath)
if err != nil {
return errors.New("Error occured while reading DeepSource config file. Exiting...")
}
// Fetch the client
deepsource, err := deepsource.New(deepsource.ClientOpts{
Token: config.Cfg.Token,
HostName: config.Cfg.Host,
})
if err != nil {
return err
}
ctx := context.Background()
// Fetch the list of supported analyzers and transformers' data
// using the SDK
err = utils.GetAnalyzersAndTransformersData(ctx, *deepsource)
if err != nil {
return err
}
// Create an instance of ConfigValidator struct
var validator configvalidator.ConfigValidator
// Send the config contents to get validated
var result configvalidator.Result = validator.ValidateConfig(content)
// Checking for all types of errors (due to viper/valid errors/no errors)
// and handling them
if result.ConfigReadError {
// handle printing viper error here
printViperError(content, result.Errors)
} else if !result.Valid {
// handle printing other errors here
printConfigErrors(result.Errors)
} else {
printValidConfig()
}
return nil
}
// Extracts the path of DeepSource config (.deepsource.toml) in the user repo
// Checks in the current working directory as well as the root directory
// of the project
func extractDSConfigPath() (string, error) {
var configPath string
// Get current working directory of user from where this command is run
cwd, err := os.Getwd()
if err != nil {
return "", errors.New("Error occured while fetching current working directory. Exiting...")
}
// Form the full path of cwd to search for .deepsource.toml
configPath = filepath.Join(cwd, ".deepsource.toml")
// Check if there is a deepsource.toml file here
if _, err = os.Stat(configPath); err != nil {
// Since, no .deepsource.toml in the cwd,
// fetching the top level directory
output, err := exec.Command("git", "rev-parse", "--show-toplevel").Output()
if err != nil {
return "", err
}
// Removing trailing null characters
path := strings.TrimRight(string(output), "\000\n")
// Check if the config exists on this path
if _, err = os.Stat(filepath.Join(path, ".deepsource.toml")); err != nil {
return "", errors.New("Error occured while looking for DeepSource config file. Exiting...")
} else {
// If found, use this as configpath
configPath = filepath.Join(path, "/.deepsource.toml")
}
}
return configPath, nil
}
// Handles printing the output when viper fails to read TOML file due to bad syntax
func printViperError(fileContent []byte, errors []string) {
var errorString string
var errorLine int
// Parsing viper error output and finding at which line bad syntax is present in
// DeepSource config TOML file
for _, error := range errors {
stripString1 := strings.Split(error, ": ")
errorString = stripString1[2]
errorLine, _ = strconv.Atoi(strings.Trim(strings.Split(stripString1[1], ", ")[0], "("))
}
// Read .deepsource.toml line by line and store in a var
lineText := strings.Split(string(fileContent), "\n")
fileLength := len(lineText)
// Print error message
pterm.Error.WithShowLineNumber(false).Printf("Error while reading config : %s\n", errorString)
pterm.Println()
// Preparing codeframe to show exactly at which line bad syntax is present in TOML file
if errorLine > 2 && errorLine+2 <= fileLength {
for i := errorLine - 2; i <= errorLine+2; i++ {
if i == errorLine {
errorStr := ""
if i >= 10 {
errorStr = fmt.Sprintf("> %d | %s", i, lineText[i-1])
} else {
errorStr = fmt.Sprintf("> %d | %s", i, lineText[i-1])
}
pterm.NewStyle(pterm.FgLightRed).Println(errorStr)
} else {
errorStr := ""
if i >= 10 {
errorStr = fmt.Sprintf(" %d | %s", i, lineText[i-1])
} else {
errorStr = fmt.Sprintf(" %d | %s", i, lineText[i-1])
}
pterm.NewStyle(pterm.FgLightYellow).Println(errorStr)
}
}
} else {
errorStr := fmt.Sprintf("> %d | %s", errorLine, lineText[errorLine-1])
pterm.NewStyle(pterm.FgLightRed).Println(errorStr)
}
}
// Handles printing the errors in the DeepSource config (.deepsource.toml)
func printConfigErrors(errors []string) {
for _, error := range errors {
pterm.Error.WithShowLineNumber(false).Println(error)
}
}
// Handles printing the valid config output
func printValidConfig() {
pterm.Success.Println("Config Valid")
}