@@ -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 {
@@ -234,16 +225,9 @@ func configFileTemplate(tools []domain.Tool) string {
234225 }
235226 } else {
236227 // 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 {
245- if runtime , ok := runtimeDependencies [toolName ]; ok {
246- if toolName == "dartanalyzer" {
228+ for _ , meta := range domain .SupportedToolsMetadata {
229+ if runtime , ok := runtimeDependencies [meta .Name ]; ok {
230+ if meta .Name == "dartanalyzer" {
247231 neededRuntimes ["dart" ] = true
248232 } else {
249233 neededRuntimes [runtime ] = true
@@ -270,18 +254,18 @@ func configFileTemplate(tools []domain.Tool) string {
270254 if len (tools ) > 0 {
271255 // Create a sorted slice of tool names
272256 var sortedTools []string
273- for uuid , name := range toolNameMap {
257+ for uuid , meta := range domain . SupportedToolsMetadata {
274258 if toolsMap [uuid ] {
275- sortedTools = append (sortedTools , name )
259+ sortedTools = append (sortedTools , meta . Name )
276260 }
277261 }
278262 sort .Strings (sortedTools )
279263
280264 // Write sorted tools
281265 for _ , name := range sortedTools {
282266 // Find the UUID for this tool name to get its version
283- for uuid , toolName := range toolNameMap {
284- if toolName == name && toolsMap [uuid ] {
267+ for uuid , meta := range domain . SupportedToolsMetadata {
268+ if meta . Name == name && toolsMap [uuid ] {
285269 version := toolVersions [uuid ]
286270 sb .WriteString (fmt .Sprintf (" - %s@%s\n " , name , version ))
287271 break
@@ -291,20 +275,10 @@ func configFileTemplate(tools []domain.Tool) string {
291275 } else {
292276 // If no tools were specified (local mode), include all tools in sorted order
293277 var sortedTools []string
294-
295- // Get supported tools from plugin system
296- supportedTools , err := plugins .GetSupportedTools ()
297- if err != nil {
298- log .Printf ("Warning: failed to get supported tools: %v" , err )
299- return sb .String ()
300- }
301-
302- // Convert map keys to slice and sort them
303- for toolName := range supportedTools {
304- if version , ok := defaultVersions [toolName ]; ok {
305- // Skip tools without a version
278+ for _ , meta := range domain .SupportedToolsMetadata {
279+ if version , ok := defaultVersions [meta .Name ]; ok {
306280 if version != "" {
307- sortedTools = append (sortedTools , toolName )
281+ sortedTools = append (sortedTools , meta . Name )
308282 }
309283 }
310284 }
@@ -353,27 +327,31 @@ func buildRepositoryConfigurationFiles(token string) error {
353327 return err
354328 }
355329
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" ,
330+ toolsWithLatestVersion , uuidToName , familyToVersions := KeepToolsWithLatestVersion (apiTools )
331+
332+ for family , versions := range familyToVersions {
333+ if len (versions ) > 1 {
334+ kept := ", "
335+ for _ , tool := range toolsWithLatestVersion {
336+ if domain .SupportedToolsMetadata [tool .Uuid ].Name == family {
337+ kept = tool .Version
338+ break
339+ }
340+ }
341+ fmt .Printf ("⚠️ Multiple versions of '%s' detected: [%s], keeping %s\n " , family , strings .Join (versions , ", " ), kept )
342+ }
365343 }
366344
367345 // Generate languages configuration based on API tools response
368- if err := tools .CreateLanguagesConfigFile (apiTools , toolsConfigDir , uuidToName , initFlags ); err != nil {
346+ if err := tools .CreateLanguagesConfigFile (toolsWithLatestVersion , toolsConfigDir , uuidToName , initFlags ); err != nil {
369347 return fmt .Errorf ("failed to create languages configuration file: %w" , err )
370348 }
371349
372350 // Filter out any tools that use configuration file
373- configuredToolsWithUI := tools .FilterToolsByConfigUsage (apiTools )
351+ configuredToolsWithUI := tools .FilterToolsByConfigUsage (toolsWithLatestVersion )
374352
375353 // Create main config files with all enabled API tools
376- err = createConfigurationFiles (apiTools , false )
354+ err = createConfigurationFiles (toolsWithLatestVersion , false )
377355 if err != nil {
378356 log .Fatal (err )
379357 }
@@ -398,43 +376,48 @@ func buildRepositoryConfigurationFiles(token string) error {
398376func createToolFileConfigurations (tool domain.Tool , patternConfiguration []domain.PatternConfiguration ) error {
399377 toolsConfigDir := config .Config .ToolsConfigDirectory ()
400378 switch tool .Uuid {
401- case ESLint :
379+ case domain . ESLint , domain . ESLint9 :
402380 err := tools .CreateEslintConfig (toolsConfigDir , patternConfiguration )
403381 if err != nil {
404382 return fmt .Errorf ("failed to write eslint config: %v" , err )
405383 }
406384 fmt .Println ("ESLint configuration created based on Codacy settings. Ignoring plugin rules. ESLint plugins are not supported yet." )
407- case Trivy :
385+ case domain . Trivy :
408386 err := createTrivyConfigFile (patternConfiguration , toolsConfigDir )
409387 if err != nil {
410388 return fmt .Errorf ("failed to create Trivy config: %v" , err )
411389 }
412390 fmt .Println ("Trivy configuration created based on Codacy settings" )
413- case PMD :
391+ case domain . PMD :
414392 err := createPMDConfigFile (patternConfiguration , toolsConfigDir )
415393 if err != nil {
416394 return fmt .Errorf ("failed to create PMD config: %v" , err )
417395 }
418- fmt .Println ("PMD configuration created based on Codacy settings" )
419- case PyLint :
396+ case domain .PMD7 :
397+ err := createPMD7ConfigFile (patternConfiguration , toolsConfigDir )
398+ if err != nil {
399+ return fmt .Errorf ("failed to create PMD7 config: %v" , err )
400+ }
401+ fmt .Println ("PMD7 configuration created based on Codacy settings" )
402+ case domain .PyLint :
420403 err := createPylintConfigFile (patternConfiguration , toolsConfigDir )
421404 if err != nil {
422405 return fmt .Errorf ("failed to create Pylint config: %v" , err )
423406 }
424407 fmt .Println ("Pylint configuration created based on Codacy settings" )
425- case DartAnalyzer :
408+ case domain . DartAnalyzer :
426409 err := createDartAnalyzerConfigFile (patternConfiguration , toolsConfigDir )
427410 if err != nil {
428411 return fmt .Errorf ("failed to create Dart Analyzer config: %v" , err )
429412 }
430413 fmt .Println ("Dart configuration created based on Codacy settings" )
431- case Semgrep :
414+ case domain . Semgrep :
432415 err := createSemgrepConfigFile (patternConfiguration , toolsConfigDir )
433416 if err != nil {
434417 return fmt .Errorf ("failed to create Semgrep config: %v" , err )
435418 }
436419 fmt .Println ("Semgrep configuration created based on Codacy settings" )
437- case Lizard :
420+ case domain . Lizard :
438421 err := createLizardConfigFile (toolsConfigDir , patternConfiguration )
439422 if err != nil {
440423 return fmt .Errorf ("failed to create Lizard config: %v" , err )
@@ -445,7 +428,12 @@ func createToolFileConfigurations(tool domain.Tool, patternConfiguration []domai
445428}
446429
447430func createPMDConfigFile (config []domain.PatternConfiguration , toolsConfigDir string ) error {
448- pmdConfigurationString := tools .CreatePmdConfig (config )
431+ pmdConfigurationString := tools .CreatePmd6Config (config )
432+ return os .WriteFile (filepath .Join (toolsConfigDir , "ruleset.xml" ), []byte (pmdConfigurationString ), utils .DefaultFilePerms )
433+ }
434+
435+ func createPMD7ConfigFile (config []domain.PatternConfiguration , toolsConfigDir string ) error {
436+ pmdConfigurationString := tools .CreatePmd7Config (config )
449437 return os .WriteFile (filepath .Join (toolsConfigDir , "ruleset.xml" ), []byte (pmdConfigurationString ), utils .DefaultFilePerms )
450438}
451439
@@ -529,37 +517,39 @@ func createLizardConfigFile(toolsConfigDir string, patternConfiguration []domain
529517
530518// buildDefaultConfigurationFiles creates default configuration files for all tools
531519func buildDefaultConfigurationFiles (toolsConfigDir string ) error {
532- for _ , tool := range AvailableTools {
533- patternsConfig , err := codacyclient .GetDefaultToolPatternsConfig (initFlags , tool )
520+ for uuid := range domain . SupportedToolsMetadata {
521+ patternsConfig , err := codacyclient .GetDefaultToolPatternsConfig (initFlags , uuid )
534522 if err != nil {
535523 return fmt .Errorf ("failed to get default tool patterns config: %w" , err )
536524 }
537- switch tool {
538- case ESLint :
525+ switch uuid {
526+ case domain . ESLint :
539527 if err := tools .CreateEslintConfig (toolsConfigDir , patternsConfig ); err != nil {
540528 return fmt .Errorf ("failed to create eslint config file: %v" , err )
541529 }
542- case Trivy :
530+ case domain . Trivy :
543531 if err := createTrivyConfigFile (patternsConfig , toolsConfigDir ); err != nil {
544532 return fmt .Errorf ("failed to create default Trivy configuration: %w" , err )
545533 }
546- case PMD :
534+ case domain . PMD :
547535 if err := createPMDConfigFile (patternsConfig , toolsConfigDir ); err != nil {
548536 return fmt .Errorf ("failed to create default PMD configuration: %w" , err )
549537 }
550- case PyLint :
538+ case domain .PMD7 , domain .ESLint9 :
539+ continue
540+ case domain .PyLint :
551541 if err := createPylintConfigFile (patternsConfig , toolsConfigDir ); err != nil {
552542 return fmt .Errorf ("failed to create default Pylint configuration: %w" , err )
553543 }
554- case DartAnalyzer :
544+ case domain . DartAnalyzer :
555545 if err := createDartAnalyzerConfigFile (patternsConfig , toolsConfigDir ); err != nil {
556546 return fmt .Errorf ("failed to create default Dart Analyzer configuration: %w" , err )
557547 }
558- case Semgrep :
548+ case domain . Semgrep :
559549 if err := createSemgrepConfigFile (patternsConfig , toolsConfigDir ); err != nil {
560550 return fmt .Errorf ("failed to create default Semgrep configuration: %w" , err )
561551 }
562- case Lizard :
552+ case domain . Lizard :
563553 if err := createLizardConfigFile (toolsConfigDir , patternsConfig ); err != nil {
564554 return fmt .Errorf ("failed to create default Lizard configuration: %w" , err )
565555 }
@@ -568,23 +558,50 @@ func buildDefaultConfigurationFiles(toolsConfigDir string) error {
568558 return nil
569559}
570560
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- )
561+ // KeepToolsWithLatestVersion filters the tools to keep only the latest version of each tool family.
562+ func KeepToolsWithLatestVersion (tools []domain.Tool ) (
563+ toolsWithLatestVersion []domain.Tool ,
564+ uuidToName map [string ]string ,
565+ familyToVersions map [string ][]string ,
566+ ) {
567+ latestTools := map [string ]domain.Tool {}
568+ uuidToName = map [string ]string {}
569+ seen := map [string ][]domain.Tool {}
570+ familyToVersions = map [string ][]string {}
571+
572+ for _ , tool := range tools {
573+ meta , ok := domain .SupportedToolsMetadata [tool .Uuid ]
574+ if ! ok {
575+ continue
576+ }
577+
578+ // Track all tools seen per family
579+ seen [meta .Name ] = append (seen [meta .Name ], tool )
580+
581+ // Pick the best version
582+ current , exists := latestTools [meta .Name ]
583+ if ! exists || domain .SupportedToolsMetadata [current .Uuid ].Priority > meta .Priority {
584+ latestTools [meta .Name ] = tool
585+ uuidToName [tool .Uuid ] = meta .Name
586+ }
587+ }
588+
589+ // Populate final list and version map for logging
590+ for family , tools := range seen {
591+ var versions []string
592+ for _ , t := range tools {
593+ v := t .Version
594+ if v == "" {
595+ v = "(unknown)"
596+ }
597+ versions = append (versions , v )
598+ }
599+ familyToVersions [family ] = versions
600+ }
601+
602+ for _ , tool := range latestTools {
603+ toolsWithLatestVersion = append (toolsWithLatestVersion , tool )
604+ }
580605
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 ,
606+ return
590607}
0 commit comments