Skip to content

Commit fba5b0e

Browse files
feat: Enhance tool language configuration with API integration
- Added support for Trivy in the tool language mapping. - Updated GetToolLanguageMappingFromAPI to dynamically fetch tool configurations from the public API. - Improved error handling and logging for API failures. - Refactored GetDefaultToolLanguageMapping to prioritize API data over hardcoded values. This update streamlines the configuration process and ensures up-to-date tool language mappings.
1 parent 292d9c7 commit fba5b0e

File tree

2 files changed

+81
-57
lines changed

2 files changed

+81
-57
lines changed

integration-tests/config-discover/expected/codacy.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ tools:
1010
1111
1212
13+

tools/language_config.go

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

33
import (
44
"fmt"
5+
"log"
56
"os"
67
"path/filepath"
78
"slices"
@@ -12,83 +13,105 @@ import (
1213
"codacy/cli-v2/config"
1314
"codacy/cli-v2/domain"
1415
"codacy/cli-v2/utils"
16+
"codacy/cli-v2/utils/logger"
1517

18+
"github.com/sirupsen/logrus"
1619
"gopkg.in/yaml.v3"
1720
)
1821

1922
//
2023
// This file is responsible for building the languages-config.yaml file.
2124
//
2225

23-
// defaultToolLanguageMap defines the default mapping of tools to their supported languages and file extensions
24-
var DefaultToolLanguageMap = map[string]domain.ToolLanguageInfo{
25-
"pylint": {
26-
Name: "pylint",
27-
Languages: []string{"Python"},
28-
Extensions: []string{".py"},
29-
},
30-
"eslint": {
31-
Name: "eslint",
32-
Languages: []string{"JavaScript", "TypeScript", "JSX", "TSX"},
33-
Extensions: []string{".js", ".jsx", ".ts", ".tsx"},
34-
},
35-
"pmd": {
36-
Name: "pmd",
37-
Languages: []string{"Java", "JavaScript", "JSP", "Velocity", "XML", "Apex", "Scala", "Ruby", "VisualForce"},
38-
Extensions: []string{".java", ".js", ".jsp", ".vm", ".xml", ".cls", ".trigger", ".scala", ".rb", ".page", ".component"},
39-
},
40-
"trivy": {
41-
Name: "trivy",
42-
Languages: []string{"Multiple"},
43-
Extensions: []string{},
44-
},
45-
"dartanalyzer": {
46-
Name: "dartanalyzer",
47-
Languages: []string{"Dart"},
48-
Extensions: []string{".dart"},
49-
},
50-
"lizard": {
51-
Name: "lizard",
52-
Languages: []string{"C", "CPP", "Java", "C#", "JavaScript", "TypeScript", "VueJS", "Objective-C", "Swift", "Python", "Ruby", "TTCN-3", "PHP", "Scala", "GDScript", "Golang", "Lua", "Rust", "Fortran", "Kotlin", "Solidity", "Erlang", "Zig", "Perl"},
53-
Extensions: []string{".c", ".cpp", ".cc", ".h", ".hpp", ".java", ".cs", ".js", ".jsx", ".ts", ".tsx", ".vue", ".m", ".swift", ".py", ".rb", ".ttcn", ".php", ".scala", ".gd", ".go", ".lua", ".rs", ".f", ".f90", ".kt", ".sol", ".erl", ".zig", ".pl"},
54-
},
55-
"semgrep": {
56-
Name: "semgrep",
57-
Languages: []string{"C", "CPP", "C#", "Generic", "Go", "Java", "JavaScript", "JSON", "Kotlin", "Python", "TypeScript", "Ruby", "Rust", "JSX", "PHP", "Scala", "Swift", "Terraform"},
58-
Extensions: []string{".c", ".cpp", ".h", ".hpp", ".cs", ".go", ".java", ".js", ".json", ".kt", ".py", ".ts", ".rb", ".rs", ".jsx", ".php", ".scala", ".swift", ".tf", ".tfvars"},
59-
},
60-
"codacy-enigma-cli": {
61-
Name: "codacy-enigma-cli",
62-
Languages: []string{"Multiple"},
63-
Extensions: []string{},
64-
},
65-
"revive": {
66-
Name: "revive",
67-
Languages: []string{"Go"},
68-
Extensions: []string{".go"},
69-
},
70-
}
71-
72-
// GetToolLanguageMappingFromAPI returns tool language mapping from API data
73-
// This can be used instead of the hardcoded DefaultToolLanguageMap
26+
// GetToolLanguageMappingFromAPI gets the tool language mapping from the public API
27+
//
28+
// TODO: cache this with TTL time
7429
func GetToolLanguageMappingFromAPI() (map[string]domain.ToolLanguageInfo, error) {
75-
configTools, err := buildToolLanguageConfigFromAPI()
30+
// Get tools from API (same as buildToolLanguageConfigFromAPI)
31+
allTools, err := codacyclient.GetToolsVersions()
7632
if err != nil {
77-
return nil, err
33+
return nil, fmt.Errorf("failed to get tools from API: %w", err)
34+
}
35+
36+
// Get language file extensions from API
37+
languageTools, err := codacyclient.GetLanguageTools()
38+
if err != nil {
39+
return nil, fmt.Errorf("failed to get language tools from API: %w", err)
40+
}
41+
42+
// Create map of language name to file extensions
43+
languageExtensionsMap := make(map[string][]string)
44+
for _, langTool := range languageTools {
45+
languageExtensionsMap[strings.ToLower(langTool.Name)] = langTool.FileExtensions
7846
}
7947

80-
// Convert slice to map for compatibility with existing code
48+
// Build the tool to language mapping (same pattern as buildToolLanguageConfigFromAPI)
8149
result := make(map[string]domain.ToolLanguageInfo)
82-
for _, tool := range configTools {
83-
result[tool.Name] = tool
50+
supportedToolNames := make(map[string]bool)
51+
52+
// Get supported tool names from metadata
53+
for _, meta := range domain.SupportedToolsMetadata {
54+
supportedToolNames[meta.Name] = true
55+
}
56+
57+
// Group tools by name and keep only supported ones
58+
toolsByName := make(map[string]domain.Tool)
59+
for _, tool := range allTools {
60+
if supportedToolNames[strings.ToLower(tool.ShortName)] {
61+
// Keep the tool with latest version (first one in the response)
62+
if _, exists := toolsByName[strings.ToLower(tool.ShortName)]; !exists {
63+
toolsByName[strings.ToLower(tool.ShortName)] = tool
64+
}
65+
}
66+
}
67+
68+
// Build configuration for each supported tool
69+
for toolName, tool := range toolsByName {
70+
configTool := domain.ToolLanguageInfo{
71+
Name: toolName,
72+
Languages: tool.Languages,
73+
Extensions: []string{},
74+
}
75+
76+
// Build extensions from API language data
77+
extensionsSet := make(map[string]struct{})
78+
for _, apiLang := range tool.Languages {
79+
lowerLang := strings.ToLower(apiLang)
80+
if extensions, exists := languageExtensionsMap[lowerLang]; exists {
81+
for _, ext := range extensions {
82+
extensionsSet[ext] = struct{}{}
83+
}
84+
}
85+
}
86+
87+
// Convert set to sorted slice
88+
for ext := range extensionsSet {
89+
configTool.Extensions = append(configTool.Extensions, ext)
90+
}
91+
slices.Sort(configTool.Extensions)
92+
93+
// Sort languages alphabetically
94+
slices.Sort(configTool.Languages)
95+
96+
result[toolName] = configTool
8497
}
8598

8699
return result, nil
87100
}
88101

89102
// GetDefaultToolLanguageMapping returns the default mapping of tools to their supported languages and file extensions
103+
// This function now uses the public API instead of hardcoded mappings.
90104
func GetDefaultToolLanguageMapping() map[string]domain.ToolLanguageInfo {
91-
return DefaultToolLanguageMap
105+
// Try to get the mapping from API, fallback to hardcoded only if API fails
106+
apiMapping, err := GetToolLanguageMappingFromAPI()
107+
if err != nil {
108+
logger.Error("Failed to get tool language mapping from API", logrus.Fields{
109+
"error": err,
110+
})
111+
// print fatal error and exit
112+
log.Fatalf("Failed to get tool language mapping from API: %v", err)
113+
}
114+
return apiMapping
92115
}
93116

94117
// buildToolLanguageConfigFromAPI builds tool language configuration using only API data

0 commit comments

Comments
 (0)