-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpmdConfigCreator.go
221 lines (186 loc) · 5.9 KB
/
pmdConfigCreator.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
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
package tools
import (
"codacy/cli-v2/domain"
_ "embed"
"encoding/xml"
"fmt"
"strings"
)
//go:embed pmd/default-ruleset.xml
var defaultPMDRuleset string
// Parameter represents a rule parameter
type Parameter struct {
Name string
Value string
}
// Rule represents a PMD rule
type Rule struct {
PatternID string
Parameters []Parameter
Enabled bool
}
// RuleSet represents the PMD ruleset XML structure
type RuleSet struct {
XMLName xml.Name `xml:"ruleset"`
Name string `xml:"name,attr"`
Description string `xml:"description"`
Rules []Rule
}
// DeprecatedReferences maps deprecated pattern IDs to their new versions
var DeprecatedReferences = map[string]string{
// Add deprecated pattern mappings here
// Example: "rulesets_java_design_ExcessiveClassLength": "category_java_design_ExcessiveClassLength",
}
// prefixPatternID adds the appropriate prefix to a pattern ID
func prefixPatternID(patternID string) string {
parts := strings.Split(patternID, "_")
// Handle different pattern ID formats
switch len(parts) {
case 2:
// Format: "patternCategory_patternName"
return fmt.Sprintf("category_java_%s_%s", parts[0], parts[1])
case 3:
// Format: "langAlias_patternCategory_patternName"
return fmt.Sprintf("category_%s_%s_%s", parts[0], parts[1], parts[2])
case 4:
// Format: "root_langAlias_patternCategory_patternName"
return fmt.Sprintf("%s_%s_%s_%s", parts[0], parts[1], parts[2], parts[3])
default:
// Return as is if format is unknown
return patternID
}
}
// convertPatternIDToPMD converts a Codacy pattern ID to PMD format
func convertPatternIDToPMD(patternID string) (string, error) {
// Check if this is a deprecated pattern
if newID, ok := DeprecatedReferences[patternID]; ok {
patternID = newID
}
// Handle both formats:
// 1. "java/design/NPathComplexity"
// 2. "PMD_category_java_design_NPathComplexity"
// 3. "PMD_category_apex_security_ApexSharingViolations"
// 4. "PMD_category_plsql_errorprone_TO_TIMESTAMPWithoutDateFormat"
var parts []string
if strings.Contains(patternID, "/") {
parts = strings.Split(patternID, "/")
} else {
// Remove PMD_ prefix if present
id := strings.TrimPrefix(patternID, "PMD_")
// Split by underscore and remove "category" if present
parts = strings.Split(id, "_")
if parts[0] == "category" {
parts = parts[1:]
}
}
if len(parts) < 3 {
return "", fmt.Errorf("invalid pattern ID format: %s", patternID)
}
// Extract language, category, and rule
language := parts[0] // java, apex, etc.
category := parts[1] // design, security, etc.
rule := parts[2] // rule name
// If there are more parts, combine them with the rule name
if len(parts) > 3 {
rule = strings.Join(parts[2:], "_")
}
return fmt.Sprintf("category/%s/%s.xml/%s", language, category, rule), nil
}
// generateRuleXML generates XML for a single rule
func generateRuleXML(rule Rule) (string, error) {
pmdRef, err := convertPatternIDToPMD(rule.PatternID)
if err != nil {
return "", err
}
if len(rule.Parameters) == 0 {
return fmt.Sprintf(` <rule ref="%s"/>`, pmdRef), nil
}
// Generate rule with parameters
var params strings.Builder
for _, param := range rule.Parameters {
if param.Name != "enabled" && param.Name != "version" { // Skip enabled and version parameters
params.WriteString(fmt.Sprintf(`
<property name="%s" value="%s"/>`, param.Name, param.Value))
}
}
return fmt.Sprintf(` <rule ref="%s">
<properties>%s
</properties>
</rule>`, pmdRef, params.String()), nil
}
// ConvertToPMDRuleset converts Codacy rules to PMD ruleset format
func ConvertToPMDRuleset(rules []Rule) (string, error) {
var rulesetXML strings.Builder
rulesetXML.WriteString(`<?xml version="1.0"?>
<ruleset name="Codacy PMD Ruleset"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
<description>Codacy PMD Ruleset</description>
`)
// Track processed rules to avoid duplicates
processedRules := make(map[string]bool)
for _, rule := range rules {
if !rule.Enabled {
continue
}
pmdRef, err := convertPatternIDToPMD(rule.PatternID)
if err != nil {
return "", fmt.Errorf("error converting pattern ID: %w", err)
}
// Skip if we've already processed this rule
if processedRules[pmdRef] {
continue
}
processedRules[pmdRef] = true
ruleXML, err := generateRuleXML(rule)
if err != nil {
return "", fmt.Errorf("error generating rule XML: %w", err)
}
rulesetXML.WriteString(ruleXML + "\n")
}
rulesetXML.WriteString("</ruleset>")
return rulesetXML.String(), nil
}
// CreatePmdConfig creates a PMD configuration from the provided tool configuration
func CreatePmdConfig(configuration []domain.PatternConfiguration) string {
// If no patterns provided, return the default ruleset
if len(configuration) == 0 {
return defaultPMDRuleset
}
// Convert ToolConfiguration to our Rule format
var rules []Rule
for _, pattern := range configuration {
// Check if pattern is enabled
patternEnabled := true
var parameters []Parameter
for _, param := range pattern.Parameters {
if param.Name == "enabled" && param.Value == "false" {
patternEnabled = false
break
} else if param.Name != "enabled" {
// Store non-enabled parameters
parameters = append(parameters, Parameter{
Name: param.Name,
Value: param.Value,
})
}
}
// Apply prefix to pattern ID if needed
patternID := pattern.PatternDefinition.Id
if !strings.HasPrefix(patternID, "PMD_") && !strings.Contains(patternID, "/") {
patternID = prefixPatternID(patternID)
}
rules = append(rules, Rule{
PatternID: patternID,
Parameters: parameters,
Enabled: patternEnabled,
})
}
// Convert rules to PMD ruleset
rulesetXML, err := ConvertToPMDRuleset(rules)
if err != nil {
return defaultPMDRuleset
}
return rulesetXML
}