-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathtool.go
131 lines (111 loc) · 4.5 KB
/
tool.go
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
package codacytool
import (
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
"github.com/samber/lo"
"github.com/sirupsen/logrus"
)
// Tool is the interface each tool must implement.
type Tool interface {
Run(ctx context.Context, toolExecution ToolExecution) ([]Result, error)
}
// ToolExecution has the data for the execution of a tool.
type ToolExecution struct {
// ToolDefinition is the metadata for the tool that will execute the analysis.
ToolDefinition ToolDefinition
// SourceDir is the directory of `Files`.
SourceDir string
// Files is an array of file paths, relative to `SourceDir`, to the files that will be analysed.
// If undefined, the analysis should include all files inside `SourceDir`.
// If empty, no analysis should be made.
Files *[]string
// Patterns is an array of the patterns (rules) to be used for analysis.
// It can be a subset of the tool's supported patterns.
// If undefined, the analysis should use the tool's configuration file, if available.
// Otherwise, use the tool's default patterns.
Patterns *[]Pattern
}
func newToolExecution(runConfig RunConfiguration) (*ToolExecution, error) {
toolDefinition, err := loadToolDefinition(runConfig)
if err != nil {
return nil, err
}
logrus.Debugf("Tool definition: %+v", toolDefinition)
analysisConfig, err := loadAnalysisConfiguration(runConfig)
if err != nil {
return nil, err
}
logrus.Debugf("Analysis configuration: %+v", analysisConfig)
var patterns *[]Pattern
if analysisConfig.Tools != nil {
configuredTool, exists := lo.Find(*analysisConfig.Tools, func(item ToolDefinition) bool {
return toolDefinition.Name == item.Name
})
// If there is no configured tool that matches the container's tool definition, patterns will be nil. The underlying tool will know what to do in that case.
// Otherwise we guarantee that the configured patterns have all the required parameters as specified in the container's tool definition.
if exists && configuredTool.Patterns != nil {
p := patternsWithDefaultParameters(*toolDefinition, configuredTool)
patterns = &p
}
}
toolExecution := ToolExecution{
ToolDefinition: *toolDefinition,
SourceDir: runConfig.SourceDir,
Files: analysisConfig.Files,
Patterns: patterns,
}
logrus.Debugf("Tool execution: %+v", toolExecution)
return &toolExecution, nil
}
// patternsWithDefaultParameters returns the patterns of `configuredTool` with any missing parameters added, as specified by `toolDefinition`.
func patternsWithDefaultParameters(toolDefinition, configuredTool ToolDefinition) []Pattern {
var patterns []Pattern
for _, configuredToolPattern := range *configuredTool.Patterns {
// Configured pattern exists in the tool definition patterns
toolDefinitionPattern, exists := lo.Find(*toolDefinition.Patterns, func(item Pattern) bool {
return configuredToolPattern.ID == item.ID
})
// Patterns have different number of parameters
if exists {
for _, toolDefintionPatternParam := range toolDefinitionPattern.Parameters {
// Add non-existing params to configured tool pattern params, as specified in the tool definition.
paramExists := lo.SomeBy(configuredToolPattern.Parameters, func(item PatternParameter) bool {
return toolDefintionPatternParam.Name == item.Name
})
if !paramExists {
logrus.Debugf("Pattern parameter added to configured tool: %+v", toolDefintionPatternParam)
configuredToolPattern.Parameters = append(
configuredToolPattern.Parameters,
toolDefintionPatternParam,
)
}
}
}
patterns = append(patterns, configuredToolPattern)
}
return patterns
}
const defaultToolDefinitionFile = "docs/patterns.json"
// ToolDefinition is the metadata of the tool to run.
type ToolDefinition struct {
Name string `json:"name"`
Version string `json:"version,omitempty"`
// Patterns contains all of the tool's supported patterns.
Patterns *[]Pattern `json:"patterns"`
}
// loadToolDefinition loads tool information from the tool definition file.
func loadToolDefinition(runConfig RunConfiguration) (*ToolDefinition, error) {
fileLocation := filepath.Join(runConfig.ToolConfigurationDir, defaultToolDefinitionFile)
fileContent, err := os.ReadFile(fileLocation)
if err != nil {
return nil, fmt.Errorf("failed to read tool definition file: %s\n%w", fileLocation, err)
}
toolDefinition := ToolDefinition{}
if err := json.Unmarshal(fileContent, &toolDefinition); err != nil {
return nil, fmt.Errorf("failed to parse tool definition file: %s\n%w", string(fileContent), err)
}
return &toolDefinition, nil
}