@@ -153,17 +153,6 @@ func createConfigurationFiles(tools []domain.Tool, cliLocalMode bool) error {
153153 return nil
154154}
155155
156- // Map tool UUIDs to their names
157- var toolNameMap = map [string ]string {
158- ESLint : "eslint" ,
159- Trivy : "trivy" ,
160- PyLint : "pylint" ,
161- PMD : "pmd" ,
162- DartAnalyzer : "dartanalyzer" ,
163- Semgrep : "semgrep" ,
164- Lizard : "lizard" ,
165- }
166-
167156// RuntimePluginConfig holds the structure of the runtime plugin.yaml file
168157type RuntimePluginConfig struct {
169158 Name string `yaml:"name"`
@@ -176,6 +165,8 @@ func configFileTemplate(tools []domain.Tool) string {
176165 toolsMap := make (map [string ]bool )
177166 toolVersions := make (map [string ]string )
178167
168+ toolsWithLatestVersion , _ , _ := KeepToolsWithLatestVersion (tools )
169+
179170 // Track needed runtimes
180171 neededRuntimes := make (map [string ]bool )
181172
@@ -189,23 +180,23 @@ func configFileTemplate(tools []domain.Tool) string {
189180 runtimeDependencies := plugins .GetToolRuntimeDependencies ()
190181
191182 // Build map of enabled tools with their versions
192- for _ , tool := range tools {
183+ for _ , tool := range toolsWithLatestVersion {
193184 toolsMap [tool .Uuid ] = true
194185 if tool .Version != "" {
195186 toolVersions [tool .Uuid ] = tool .Version
196187 } else {
197- toolName := toolNameMap [tool .Uuid ]
198- if defaultVersion , ok := defaultVersions [toolName ]; ok {
199- toolVersions [tool .Uuid ] = defaultVersion
188+ if meta , ok := domain .SupportedToolsMetadata [tool .Uuid ]; ok {
189+ if defaultVersion , ok := defaultVersions [meta .Name ]; ok {
190+ toolVersions [tool .Uuid ] = defaultVersion
191+ }
200192 }
201193 }
202194
203195 // Get the tool's runtime dependency
204- toolName := toolNameMap [tool .Uuid ]
205- if toolName != "" {
206- if runtime , ok := runtimeDependencies [toolName ]; ok {
196+ if meta , ok := domain .SupportedToolsMetadata [tool .Uuid ]; ok {
197+ if runtime , ok := runtimeDependencies [meta .Name ]; ok {
207198 // Handle special case for dartanalyzer which can use either dart or flutter
208- if toolName == "dartanalyzer" {
199+ if meta . Name == "dartanalyzer" {
209200 // For now, default to dart runtime
210201 neededRuntimes ["dart" ] = true
211202 } else {
@@ -233,15 +224,8 @@ func configFileTemplate(tools []domain.Tool) string {
233224 sb .WriteString (fmt .Sprintf (" - %s@%s\n " , runtime , runtimeVersions [runtime ]))
234225 }
235226 } else {
236- // In local mode with no tools specified, include only the necessary runtimes
237- supportedTools , err := plugins .GetSupportedTools ()
238- if err != nil {
239- log .Printf ("Warning: failed to get supported tools: %v" , err )
240- return sb .String ()
241- }
242-
243- // Get runtimes needed by supported tools
244- for toolName := range supportedTools {
227+ // If no tools were specified (local mode), include all tools in sorted order
228+ for toolName := range defaultVersions {
245229 if runtime , ok := runtimeDependencies [toolName ]; ok {
246230 if toolName == "dartanalyzer" {
247231 neededRuntimes ["dart" ] = true
@@ -250,38 +234,33 @@ func configFileTemplate(tools []domain.Tool) string {
250234 }
251235 }
252236 }
253-
254- // Create a sorted slice of runtimes
255237 var sortedRuntimes []string
256238 for runtime := range neededRuntimes {
257239 sortedRuntimes = append (sortedRuntimes , runtime )
258240 }
259241 sort .Strings (sortedRuntimes )
260-
261- // Write sorted runtimes
262242 for _ , runtime := range sortedRuntimes {
263243 sb .WriteString (fmt .Sprintf (" - %s@%s\n " , runtime , runtimeVersions [runtime ]))
264244 }
265245 }
266246
267247 sb .WriteString ("tools:\n " )
268248
269- // If we have tools from the API (enabled tools), use only those
270249 if len (tools ) > 0 {
271250 // Create a sorted slice of tool names
272251 var sortedTools []string
273- for uuid , name := range toolNameMap {
252+ for uuid , meta := range domain . SupportedToolsMetadata {
274253 if toolsMap [uuid ] {
275- sortedTools = append (sortedTools , name )
254+ sortedTools = append (sortedTools , meta . Name )
276255 }
277256 }
278257 sort .Strings (sortedTools )
279258
280259 // Write sorted tools
281260 for _ , name := range sortedTools {
282261 // Find the UUID for this tool name to get its version
283- for uuid , toolName := range toolNameMap {
284- if toolName == name && toolsMap [uuid ] {
262+ for uuid , meta := range domain . SupportedToolsMetadata {
263+ if meta . Name == name && toolsMap [uuid ] {
285264 version := toolVersions [uuid ]
286265 sb .WriteString (fmt .Sprintf (" - %s@%s\n " , name , version ))
287266 break
@@ -353,27 +332,31 @@ func buildRepositoryConfigurationFiles(token string) error {
353332 return err
354333 }
355334
356- // Map UUID to tool shortname for lookup
357- uuidToName := map [string ]string {
358- ESLint : "eslint" ,
359- Trivy : "trivy" ,
360- PyLint : "pylint" ,
361- PMD : "pmd" ,
362- DartAnalyzer : "dartanalyzer" ,
363- Lizard : "lizard" ,
364- Semgrep : "semgrep" ,
335+ toolsWithLatestVersion , uuidToName , familyToVersions := KeepToolsWithLatestVersion (apiTools )
336+
337+ for family , versions := range familyToVersions {
338+ if len (versions ) > 1 {
339+ kept := ", "
340+ for _ , tool := range toolsWithLatestVersion {
341+ if domain .SupportedToolsMetadata [tool .Uuid ].Name == family {
342+ kept = tool .Version
343+ break
344+ }
345+ }
346+ fmt .Printf ("⚠️ Multiple versions of '%s' detected: [%s], keeping %s\n " , family , strings .Join (versions , ", " ), kept )
347+ }
365348 }
366349
367350 // Generate languages configuration based on API tools response
368- if err := tools .CreateLanguagesConfigFile (apiTools , toolsConfigDir , uuidToName , initFlags ); err != nil {
351+ if err := tools .CreateLanguagesConfigFile (toolsWithLatestVersion , toolsConfigDir , uuidToName , initFlags ); err != nil {
369352 return fmt .Errorf ("failed to create languages configuration file: %w" , err )
370353 }
371354
372355 // Filter out any tools that use configuration file
373- configuredToolsWithUI := tools .FilterToolsByConfigUsage (apiTools )
356+ configuredToolsWithUI := tools .FilterToolsByConfigUsage (toolsWithLatestVersion )
374357
375358 // Create main config files with all enabled API tools
376- err = createConfigurationFiles (apiTools , false )
359+ err = createConfigurationFiles (toolsWithLatestVersion , false )
377360 if err != nil {
378361 log .Fatal (err )
379362 }
@@ -398,43 +381,48 @@ func buildRepositoryConfigurationFiles(token string) error {
398381func createToolFileConfigurations (tool domain.Tool , patternConfiguration []domain.PatternConfiguration ) error {
399382 toolsConfigDir := config .Config .ToolsConfigDirectory ()
400383 switch tool .Uuid {
401- case ESLint :
384+ case domain . ESLint , domain . ESLint9 :
402385 err := tools .CreateEslintConfig (toolsConfigDir , patternConfiguration )
403386 if err != nil {
404387 return fmt .Errorf ("failed to write eslint config: %v" , err )
405388 }
406389 fmt .Println ("ESLint configuration created based on Codacy settings. Ignoring plugin rules. ESLint plugins are not supported yet." )
407- case Trivy :
390+ case domain . Trivy :
408391 err := createTrivyConfigFile (patternConfiguration , toolsConfigDir )
409392 if err != nil {
410393 return fmt .Errorf ("failed to create Trivy config: %v" , err )
411394 }
412395 fmt .Println ("Trivy configuration created based on Codacy settings" )
413- case PMD :
396+ case domain . PMD :
414397 err := createPMDConfigFile (patternConfiguration , toolsConfigDir )
415398 if err != nil {
416399 return fmt .Errorf ("failed to create PMD config: %v" , err )
417400 }
418- fmt .Println ("PMD configuration created based on Codacy settings" )
419- case PyLint :
401+ case domain .PMD7 :
402+ err := createPMD7ConfigFile (patternConfiguration , toolsConfigDir )
403+ if err != nil {
404+ return fmt .Errorf ("failed to create PMD7 config: %v" , err )
405+ }
406+ fmt .Println ("PMD7 configuration created based on Codacy settings" )
407+ case domain .PyLint :
420408 err := createPylintConfigFile (patternConfiguration , toolsConfigDir )
421409 if err != nil {
422410 return fmt .Errorf ("failed to create Pylint config: %v" , err )
423411 }
424412 fmt .Println ("Pylint configuration created based on Codacy settings" )
425- case DartAnalyzer :
413+ case domain . DartAnalyzer :
426414 err := createDartAnalyzerConfigFile (patternConfiguration , toolsConfigDir )
427415 if err != nil {
428416 return fmt .Errorf ("failed to create Dart Analyzer config: %v" , err )
429417 }
430418 fmt .Println ("Dart configuration created based on Codacy settings" )
431- case Semgrep :
419+ case domain . Semgrep :
432420 err := createSemgrepConfigFile (patternConfiguration , toolsConfigDir )
433421 if err != nil {
434422 return fmt .Errorf ("failed to create Semgrep config: %v" , err )
435423 }
436424 fmt .Println ("Semgrep configuration created based on Codacy settings" )
437- case Lizard :
425+ case domain . Lizard :
438426 err := createLizardConfigFile (toolsConfigDir , patternConfiguration )
439427 if err != nil {
440428 return fmt .Errorf ("failed to create Lizard config: %v" , err )
@@ -445,7 +433,12 @@ func createToolFileConfigurations(tool domain.Tool, patternConfiguration []domai
445433}
446434
447435func createPMDConfigFile (config []domain.PatternConfiguration , toolsConfigDir string ) error {
448- pmdConfigurationString := tools .CreatePmdConfig (config )
436+ pmdConfigurationString := tools .CreatePmd6Config (config )
437+ return os .WriteFile (filepath .Join (toolsConfigDir , "ruleset.xml" ), []byte (pmdConfigurationString ), utils .DefaultFilePerms )
438+ }
439+
440+ func createPMD7ConfigFile (config []domain.PatternConfiguration , toolsConfigDir string ) error {
441+ pmdConfigurationString := tools .CreatePmd7Config (config )
449442 return os .WriteFile (filepath .Join (toolsConfigDir , "ruleset.xml" ), []byte (pmdConfigurationString ), utils .DefaultFilePerms )
450443}
451444
@@ -529,37 +522,39 @@ func createLizardConfigFile(toolsConfigDir string, patternConfiguration []domain
529522
530523// buildDefaultConfigurationFiles creates default configuration files for all tools
531524func buildDefaultConfigurationFiles (toolsConfigDir string ) error {
532- for _ , tool := range AvailableTools {
533- patternsConfig , err := codacyclient .GetDefaultToolPatternsConfig (initFlags , tool )
525+ for uuid := range domain . SupportedToolsMetadata {
526+ patternsConfig , err := codacyclient .GetDefaultToolPatternsConfig (initFlags , uuid )
534527 if err != nil {
535528 return fmt .Errorf ("failed to get default tool patterns config: %w" , err )
536529 }
537- switch tool {
538- case ESLint :
530+ switch uuid {
531+ case domain . ESLint :
539532 if err := tools .CreateEslintConfig (toolsConfigDir , patternsConfig ); err != nil {
540533 return fmt .Errorf ("failed to create eslint config file: %v" , err )
541534 }
542- case Trivy :
535+ case domain . Trivy :
543536 if err := createTrivyConfigFile (patternsConfig , toolsConfigDir ); err != nil {
544537 return fmt .Errorf ("failed to create default Trivy configuration: %w" , err )
545538 }
546- case PMD :
539+ case domain . PMD :
547540 if err := createPMDConfigFile (patternsConfig , toolsConfigDir ); err != nil {
548541 return fmt .Errorf ("failed to create default PMD configuration: %w" , err )
549542 }
550- case PyLint :
543+ case domain .PMD7 , domain .ESLint9 :
544+ continue
545+ case domain .PyLint :
551546 if err := createPylintConfigFile (patternsConfig , toolsConfigDir ); err != nil {
552547 return fmt .Errorf ("failed to create default Pylint configuration: %w" , err )
553548 }
554- case DartAnalyzer :
549+ case domain . DartAnalyzer :
555550 if err := createDartAnalyzerConfigFile (patternsConfig , toolsConfigDir ); err != nil {
556551 return fmt .Errorf ("failed to create default Dart Analyzer configuration: %w" , err )
557552 }
558- case Semgrep :
553+ case domain . Semgrep :
559554 if err := createSemgrepConfigFile (patternsConfig , toolsConfigDir ); err != nil {
560555 return fmt .Errorf ("failed to create default Semgrep configuration: %w" , err )
561556 }
562- case Lizard :
557+ case domain . Lizard :
563558 if err := createLizardConfigFile (toolsConfigDir , patternsConfig ); err != nil {
564559 return fmt .Errorf ("failed to create default Lizard configuration: %w" , err )
565560 }
@@ -568,23 +563,50 @@ func buildDefaultConfigurationFiles(toolsConfigDir string) error {
568563 return nil
569564}
570565
571- const (
572- ESLint string = "f8b29663-2cb2-498d-b923-a10c6a8c05cd"
573- Trivy string = "2fd7fbe0-33f9-4ab3-ab73-e9b62404e2cb"
574- PMD string = "9ed24812-b6ee-4a58-9004-0ed183c45b8f"
575- PyLint string = "31677b6d-4ae0-4f56-8041-606a8d7a8e61"
576- DartAnalyzer string = "d203d615-6cf1-41f9-be5f-e2f660f7850f"
577- Semgrep string = "6792c561-236d-41b7-ba5e-9d6bee0d548b"
578- Lizard string = "76348462-84b3-409a-90d3-955e90abfb87"
579- )
566+ // KeepToolsWithLatestVersion filters the tools to keep only the latest version of each tool family.
567+ func KeepToolsWithLatestVersion (tools []domain.Tool ) (
568+ toolsWithLatestVersion []domain.Tool ,
569+ uuidToName map [string ]string ,
570+ familyToVersions map [string ][]string ,
571+ ) {
572+ latestTools := map [string ]domain.Tool {}
573+ uuidToName = map [string ]string {}
574+ seen := map [string ][]domain.Tool {}
575+ familyToVersions = map [string ][]string {}
576+
577+ for _ , tool := range tools {
578+ meta , ok := domain .SupportedToolsMetadata [tool .Uuid ]
579+ if ! ok {
580+ continue
581+ }
582+
583+ // Track all tools seen per family
584+ seen [meta .Name ] = append (seen [meta .Name ], tool )
585+
586+ // Pick the best version
587+ current , exists := latestTools [meta .Name ]
588+ if ! exists || domain .SupportedToolsMetadata [current .Uuid ].Priority > meta .Priority {
589+ latestTools [meta .Name ] = tool
590+ uuidToName [tool .Uuid ] = meta .Name
591+ }
592+ }
593+
594+ // Populate final list and version map for logging
595+ for family , tools := range seen {
596+ var versions []string
597+ for _ , t := range tools {
598+ v := t .Version
599+ if v == "" {
600+ v = "(unknown)"
601+ }
602+ versions = append (versions , v )
603+ }
604+ familyToVersions [family ] = versions
605+ }
606+
607+ for _ , tool := range latestTools {
608+ toolsWithLatestVersion = append (toolsWithLatestVersion , tool )
609+ }
580610
581- // AvailableTools lists all tool UUIDs supported by Codacy CLI.
582- var AvailableTools = []string {
583- ESLint ,
584- Trivy ,
585- PMD ,
586- PyLint ,
587- DartAnalyzer ,
588- Semgrep ,
589- Lizard ,
611+ return
590612}
0 commit comments