Skip to content

Commit 7432685

Browse files
committed
[PLUTO-1392] Config
1 parent 7f63eb6 commit 7432685

File tree

12 files changed

+906
-64
lines changed

12 files changed

+906
-64
lines changed

cmd/analyze.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cmd
22

33
import (
44
"codacy/cli-v2/config"
5+
"codacy/cli-v2/domain"
56
"codacy/cli-v2/plugins"
67
"codacy/cli-v2/tools"
78
"codacy/cli-v2/tools/lizard"
@@ -250,12 +251,30 @@ func runLizardAnalysis(workDirectory string, pathsToCheck []string, outputFile s
250251
lizardTool := config.Config.Tools()["lizard"]
251252

252253
if lizardTool == nil {
253-
log.Fatal("Lizard tool configuration not found")
254+
log.Fatal("Lizard plugin configuration not found")
254255
}
255256

256257
lizardBinary := lizardTool.Binaries["python"]
257258

258-
return lizard.RunLizard(workDirectory, lizardBinary, pathsToCheck, outputFile, outputFormat)
259+
configFile, exists := tools.ConfigFileExists(config.Config, "lizard.yaml")
260+
var patterns []domain.PatternDefinition
261+
var err error
262+
263+
if exists {
264+
// Configuration exists, read from file
265+
patterns, err = lizard.ReadConfig(configFile)
266+
if err != nil {
267+
return fmt.Errorf("error reading config file: %v", err)
268+
}
269+
} else {
270+
fmt.Println("No configuration file found, fetching default patterns from Codacy API...")
271+
patterns, err = tools.FetchDefaultEnabledPatterns(Lizard)
272+
if err != nil {
273+
return fmt.Errorf("failed to fetch default patterns: %v", err)
274+
}
275+
}
276+
277+
return lizard.RunLizard(workDirectory, lizardBinary, pathsToCheck, outputFile, outputFormat, patterns)
259278
}
260279

261280
var analyzeCmd = &cobra.Command{

cmd/init.go

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"codacy/cli-v2/config"
55
"codacy/cli-v2/domain"
66
"codacy/cli-v2/tools"
7+
"codacy/cli-v2/tools/lizard"
78
"codacy/cli-v2/tools/pylint"
89
"codacy/cli-v2/utils"
910
"encoding/json"
@@ -65,6 +66,10 @@ var initCmd = &cobra.Command{
6566
if err != nil {
6667
log.Fatal(err)
6768
}
69+
// Create default configuration files
70+
if err := buildDefaultConfigurationFiles(toolsConfigDir); err != nil {
71+
log.Fatal(err)
72+
}
6873
} else {
6974
err := buildRepositoryConfigurationFiles(initFlags.apiToken)
7075
if err != nil {
@@ -411,6 +416,8 @@ func createToolFileConfigurations(tool tools.Tool, patternConfiguration []domain
411416
return fmt.Errorf("failed to create Semgrep config: %v", err)
412417
}
413418
}
419+
case Lizard:
420+
createLizardConfigFile(toolsConfigDir, patternConfiguration)
414421
}
415422
return nil
416423
}
@@ -423,7 +430,6 @@ func createPMDConfigFile(config []domain.PatternConfiguration, toolsConfigDir st
423430
func createDefaultPMDConfigFile(toolsConfigDir string) error {
424431
content := tools.CreatePmdConfig([]domain.PatternConfiguration{})
425432
return os.WriteFile(filepath.Join(toolsConfigDir, "ruleset.xml"), []byte(content), utils.DefaultFilePerms)
426-
427433
}
428434

429435
func createPylintConfigFile(config []domain.PatternConfiguration, toolsConfigDir string) error {
@@ -516,6 +522,49 @@ func cleanConfigDirectory(toolsConfigDir string) error {
516522
return nil
517523
}
518524

525+
func createLizardConfigFile(toolsConfigDir string, patternConfiguration []domain.PatternConfiguration) error {
526+
var patterns []domain.PatternDefinition
527+
528+
if len(patternConfiguration) == 0 {
529+
fmt.Println("Using default Lizard configuration")
530+
var err error
531+
patterns, err = tools.FetchDefaultEnabledPatterns(Lizard)
532+
if err != nil {
533+
return err
534+
}
535+
} else {
536+
patterns = make([]domain.PatternDefinition, len(patternConfiguration))
537+
for i, pattern := range patternConfiguration {
538+
patterns[i] = pattern.PatternDefinition
539+
}
540+
541+
fmt.Println("Lizard configuration created based on Codacy settings")
542+
}
543+
544+
content, err := lizard.CreateLizardConfig(patterns)
545+
if err != nil {
546+
return fmt.Errorf("failed to create Lizard configuration: %w", err)
547+
}
548+
549+
return os.WriteFile(filepath.Join(toolsConfigDir, "lizard.yaml"), []byte(content), utils.DefaultFilePerms)
550+
}
551+
552+
// buildDefaultConfigurationFiles creates default configuration files for all tools
553+
func buildDefaultConfigurationFiles(toolsConfigDir string) error {
554+
// Create default Lizard configuration
555+
if err := createLizardConfigFile(toolsConfigDir, []domain.PatternConfiguration{}); err != nil {
556+
return fmt.Errorf("failed to create default Lizard configuration: %w", err)
557+
}
558+
559+
// Add other default tool configurations here as needed
560+
// For example:
561+
// if err := createDefaultEslintConfigFile(toolsConfigDir); err != nil {
562+
// return fmt.Errorf("failed to create default ESLint configuration: %w", err)
563+
// }
564+
565+
return nil
566+
}
567+
519568
const (
520569
ESLint string = "f8b29663-2cb2-498d-b923-a10c6a8c05cd"
521570
Trivy string = "2fd7fbe0-33f9-4ab3-ab73-e9b62404e2cb"

domain/patternConfiguration.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package domain
22

33
type ParameterConfiguration struct {
4-
Name string `json:"name"`
5-
Value string `json:"value"`
4+
Name string `json:"name"`
5+
Value string `json:"value,omitempty"`
6+
Default string `json:"default,omitempty"`
67
}
78

89
type PatternDefinition struct {
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package lizard
2+
3+
import (
4+
"codacy/cli-v2/domain"
5+
"fmt"
6+
"os"
7+
"strconv"
8+
"strings"
9+
10+
"gopkg.in/yaml.v3"
11+
)
12+
13+
// CreateLizardConfig generates a Lizard configuration file content based on the API configuration
14+
func CreateLizardConfig(patterns []domain.PatternDefinition) (string, error) {
15+
patternInfo := make(map[string]map[string]interface{})
16+
17+
for _, pattern := range patterns {
18+
metricType := getMetricTypeFromPatternId(pattern.Id)
19+
if metricType == "" {
20+
fmt.Printf("Warning: Invalid pattern ID format: %s\n", pattern.Id)
21+
continue
22+
}
23+
24+
threshold := getThresholdFromParams(pattern.Parameters)
25+
if threshold != 0 {
26+
// Create a unique key for this pattern that includes the severity
27+
patternKey := pattern.Id
28+
patternInfo[patternKey] = map[string]interface{}{
29+
"id": pattern.Id,
30+
"category": pattern.Category,
31+
"level": pattern.Level,
32+
"severityLevel": pattern.SeverityLevel,
33+
"title": pattern.Title,
34+
"description": pattern.Description,
35+
"explanation": pattern.Explanation,
36+
"timeToFix": pattern.TimeToFix,
37+
"threshold": threshold,
38+
}
39+
}
40+
}
41+
42+
config := map[string]interface{}{
43+
"patterns": patternInfo,
44+
}
45+
46+
yamlData, err := yaml.Marshal(config)
47+
if err != nil {
48+
return "", fmt.Errorf("failed to marshal YAML: %w", err)
49+
}
50+
51+
return string(yamlData), nil
52+
}
53+
54+
// getThresholdFromParams extracts the threshold value from the parameters
55+
func getThresholdFromParams(params []domain.ParameterConfiguration) int {
56+
for _, param := range params {
57+
if param.Name == "threshold" {
58+
if param.Value != "" {
59+
threshold, err := strconv.Atoi(param.Value)
60+
if err == nil {
61+
return threshold
62+
}
63+
} else if param.Default != "" {
64+
threshold, err := strconv.Atoi(param.Default)
65+
if err == nil {
66+
return threshold
67+
}
68+
}
69+
}
70+
}
71+
return 0
72+
}
73+
74+
// getMetricTypeFromPatternId extracts the metric type from the pattern ID
75+
func getMetricTypeFromPatternId(patternID string) string {
76+
// Pattern IDs are in the format "Lizard_metric-severity"
77+
parts := strings.Split(patternID, "_")
78+
if len(parts) != 2 {
79+
fmt.Printf("Warning: Invalid pattern ID format: %s\n", patternID)
80+
return ""
81+
}
82+
83+
// Extract the metric type from the second part
84+
// For patterns like "file-nloc-critical", we need to get "file-nloc"
85+
metricParts := strings.Split(parts[1], "-")
86+
if len(metricParts) < 2 {
87+
fmt.Printf("Warning: Invalid metric format: %s\n", parts[1])
88+
return ""
89+
}
90+
91+
// Handle compound metric types
92+
metricType := metricParts[0]
93+
if len(metricParts) > 2 {
94+
// For patterns like "file-nloc-critical", combine "file" and "nloc"
95+
metricType = metricParts[0] + "-" + metricParts[1]
96+
}
97+
98+
// Validating that the metric type is one of the known types
99+
switch metricType {
100+
case "ccn":
101+
return "ccn"
102+
case "nloc":
103+
return "nloc"
104+
case "file-nloc":
105+
return "file-nloc"
106+
case "parameter-count":
107+
return "parameter-count"
108+
default:
109+
fmt.Printf("Warning: Unknown metric type: %s\n", metricType)
110+
return ""
111+
}
112+
}
113+
114+
// ReadConfig reads and parses the Lizard configuration file
115+
func ReadConfig(configPath string) ([]domain.PatternDefinition, error) {
116+
data, err := os.ReadFile(configPath)
117+
if err != nil {
118+
return nil, fmt.Errorf("failed to read config file: %w", err)
119+
}
120+
121+
var config map[string]map[string]map[string]interface{}
122+
if err := yaml.Unmarshal(data, &config); err != nil {
123+
return nil, fmt.Errorf("failed to parse config file: %w", err)
124+
}
125+
126+
var patterns []domain.PatternDefinition
127+
for _, pattern := range config["patterns"] {
128+
threshold, ok := pattern["threshold"].(int)
129+
if !ok {
130+
continue
131+
}
132+
133+
patterns = append(patterns, domain.PatternDefinition{
134+
Id: pattern["id"].(string),
135+
Category: pattern["category"].(string),
136+
Level: pattern["level"].(string),
137+
SeverityLevel: pattern["severityLevel"].(string),
138+
Title: pattern["title"].(string),
139+
Description: pattern["description"].(string),
140+
Explanation: pattern["explanation"].(string),
141+
TimeToFix: pattern["timeToFix"].(int),
142+
Parameters: []domain.ParameterConfiguration{
143+
{
144+
Name: "threshold",
145+
Value: fmt.Sprintf("%d", threshold),
146+
Default: fmt.Sprintf("%d", threshold),
147+
},
148+
},
149+
})
150+
}
151+
152+
return patterns, nil
153+
}

0 commit comments

Comments
 (0)